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
This commit is contained in:
Andy 2018-05-22 11:01:18 -07:00 committed by GitHub
parent 7fb3123984
commit 7106a587cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 149 additions and 117 deletions

View File

@ -158,7 +158,7 @@ namespace ts {
* 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)
* This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations.
*/
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, arg0, arg1, arg2);
}

View File

@ -313,11 +313,11 @@ namespace ts {
getSuggestionDiagnostics: file => {
return (suggestionDiagnostics.get(file.fileName) || emptyArray).concat(getUnusedDiagnostics());
function getUnusedDiagnostics(): ReadonlyArray<Diagnostic> {
function getUnusedDiagnostics(): ReadonlyArray<DiagnosticWithLocation> {
if (file.isDeclarationFile) return emptyArray;
checkSourceFile(file);
const diagnostics: Diagnostic[] = [];
const diagnostics: DiagnosticWithLocation[] = [];
Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked));
checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (kind, diag) => {
if (!unusedIsError(kind)) {
@ -481,7 +481,7 @@ namespace ts {
const diagnostics = createDiagnosticCollection();
// Suggestion diagnostics must have a file. Keyed by source file name.
const suggestionDiagnostics = createMultiMap<Diagnostic>();
const suggestionDiagnostics = createMultiMap<DiagnosticWithLocation>();
const enum TypeFacts {
None = 0,
@ -628,7 +628,7 @@ namespace ts {
Local,
Parameter,
}
type AddUnusedDiagnostic = (type: UnusedKind, diagnostic: Diagnostic) => void;
type AddUnusedDiagnostic = (type: UnusedKind, diagnostic: DiagnosticWithLocation) => void;
const builtinGlobals = createSymbolTable();
builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol);
@ -824,7 +824,7 @@ namespace ts {
diagnostics.add(diagnostic);
}
function addErrorOrSuggestion(isError: boolean, diagnostic: Diagnostic) {
function addErrorOrSuggestion(isError: boolean, diagnostic: DiagnosticWithLocation) {
if (isError) {
diagnostics.add(diagnostic);
}

View File

@ -14,8 +14,8 @@ namespace ts {
return pathIsRelative(moduleName) || isRootedDiskPath(moduleName);
}
export function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): Diagnostic[] {
return sortAndDeduplicate(diagnostics, compareDiagnostics);
export function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: ReadonlyArray<T>): T[] {
return sortAndDeduplicate<T>(diagnostics, compareDiagnostics);
}
}
@ -1619,8 +1619,8 @@ namespace ts {
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key] || message.message;
}
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number)[]): Diagnostic;
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): Diagnostic {
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number)[]): DiagnosticWithLocation;
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): DiagnosticWithLocation {
Debug.assertGreaterThanOrEqual(start, 0);
Debug.assertGreaterThanOrEqual(length, 0);

View File

@ -595,7 +595,7 @@ namespace ts {
// tslint:enable variable-name
let sourceFile: SourceFile;
let parseDiagnostics: Diagnostic[];
let parseDiagnostics: DiagnosticWithLocation[];
let syntaxCursor: IncrementalParser.SyntaxCursor;
let currentToken: SyntaxKind;

View File

@ -394,8 +394,8 @@ namespace ts {
return resolutions;
}
interface DiagnosticCache {
perFile?: Map<Diagnostic[]>;
interface DiagnosticCache<T extends Diagnostic> {
perFile?: Map<T[]>;
allDiagnostics?: Diagnostic[];
}
@ -454,7 +454,7 @@ namespace ts {
export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): ReadonlyArray<Diagnostic> {
return configFileParseResult.options.configFile ?
configFileParseResult.options.configFile.parseDiagnostics.concat(configFileParseResult.errors) :
[...configFileParseResult.options.configFile.parseDiagnostics, ...configFileParseResult.errors] :
configFileParseResult.errors;
}
@ -517,8 +517,8 @@ namespace ts {
let classifiableNames: UnderscoreEscapedMap<true>;
let modifiedFilePaths: Path[] | undefined;
const cachedSemanticDiagnosticsForFile: DiagnosticCache = {};
const cachedDeclarationDiagnosticsForFile: DiagnosticCache = {};
const cachedSemanticDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective>();
let fileProcessingDiagnostics = createDiagnosticCollection();
@ -1313,10 +1313,10 @@ namespace ts {
return filesByName.get(path);
}
function getDiagnosticsHelper(
function getDiagnosticsHelper<T extends Diagnostic>(
sourceFile: SourceFile,
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => ReadonlyArray<Diagnostic>,
cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => ReadonlyArray<T>,
cancellationToken: CancellationToken): ReadonlyArray<T> {
if (sourceFile) {
return getDiagnostics(sourceFile, cancellationToken);
}
@ -1328,7 +1328,7 @@ namespace ts {
}));
}
function getSyntacticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
function getSyntacticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken);
}
@ -1336,7 +1336,7 @@ namespace ts {
return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken);
}
function getDeclarationDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
function getDeclarationDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
const options = program.getCompilerOptions();
// collect diagnostics from the program only once if either no source file was specified or out/outFile is set (bundled emit)
if (!sourceFile || options.out || options.outFile) {
@ -1347,7 +1347,7 @@ namespace ts {
}
}
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): ReadonlyArray<Diagnostic> {
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): ReadonlyArray<DiagnosticWithLocation> {
// For JavaScript files, we report semantic errors for using TypeScript-only
// constructs from within a JavaScript file as syntactic errors.
if (isSourceFileJavaScript(sourceFile)) {
@ -1382,7 +1382,7 @@ namespace ts {
}
}
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<Diagnostic> {
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedSemanticDiagnosticsForFile, getSemanticDiagnosticsForFileNoCache);
}
@ -1403,15 +1403,22 @@ namespace ts {
// By default, only type-check .ts, .tsx, 'Deferred' and 'External' files (external files are added by plugins)
const includeBindAndCheckDiagnostics = sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX ||
sourceFile.scriptKind === ScriptKind.External || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred;
const bindDiagnostics = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
const bindDiagnostics: ReadonlyArray<Diagnostic> = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
const checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray;
const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics.getDiagnostics(sourceFile.fileName);
const programDiagnosticsInFile = programDiagnostics.getDiagnostics(sourceFile.fileName);
let diagnostics = bindDiagnostics.concat(checkDiagnostics, fileProcessingDiagnosticsInFile, programDiagnosticsInFile);
if (isCheckJs) {
diagnostics = concatenate(diagnostics, sourceFile.jsDocDiagnostics);
let diagnostics: Diagnostic[] | undefined;
for (const diags of [bindDiagnostics, checkDiagnostics, fileProcessingDiagnosticsInFile, programDiagnosticsInFile, isCheckJs ? sourceFile.jsDocDiagnostics : undefined]) {
if (diags) {
for (const diag of diags) {
if (shouldReportDiagnostic(diag)) {
diagnostics = append(diagnostics, diag);
}
}
}
}
return filter(diagnostics, shouldReportDiagnostic);
return diagnostics;
});
}
@ -1440,9 +1447,9 @@ namespace ts {
return true;
}
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
return runWithCancellationToken(() => {
const diagnostics: Diagnostic[] = [];
const diagnostics: DiagnosticWithLocation[] = [];
let parent: Node = sourceFile;
walk(sourceFile);
@ -1610,20 +1617,20 @@ namespace ts {
}
}
function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
const start = nodes.pos;
return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2);
}
// Since these are syntactic diagnostics, parent might not have been set
// this means the sourceFile cannot be infered from the node
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation {
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
}
});
}
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken): Diagnostic[] {
function getDeclarationDiagnosticsWorker(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache);
}
@ -1635,15 +1642,16 @@ namespace ts {
});
}
function getAndCacheDiagnostics(
function getAndCacheDiagnostics<T extends Diagnostic>(
sourceFile: SourceFile | undefined,
cancellationToken: CancellationToken,
cache: DiagnosticCache,
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[]) {
cache: DiagnosticCache<T>,
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => T[],
): ReadonlyArray<T> {
const cachedResult = sourceFile
? cache.perFile && cache.perFile.get(sourceFile.path)
: cache.allDiagnostics;
: cache.allDiagnostics as T[];
if (cachedResult) {
return cachedResult;
@ -1651,7 +1659,7 @@ namespace ts {
const result = getDiagnostics(sourceFile, cancellationToken) || emptyArray;
if (sourceFile) {
if (!cache.perFile) {
cache.perFile = createMap<Diagnostic[]>();
cache.perFile = createMap<T[]>();
}
cache.perFile.set(sourceFile.path, result);
}
@ -1661,7 +1669,7 @@ namespace ts {
return result;
}
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken);
}

View File

@ -90,7 +90,7 @@ namespace ts {
let onSubstituteNode: TransformationContext["onSubstituteNode"] = (_, node) => node;
let onEmitNode: TransformationContext["onEmitNode"] = (hint, node, callback) => callback(hint, node);
let state = TransformationState.Uninitialized;
const diagnostics: Diagnostic[] = [];
const diagnostics: DiagnosticWithLocation[] = [];
// The transformation context is provided to each transformer as part of transformer
// initialization.

View File

@ -1,6 +1,6 @@
/*@internal*/
namespace ts {
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): Diagnostic[] {
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] {
if (file && isSourceFileJavaScript(file)) {
return []; // No declaration diagnostics for js for now
}

View File

@ -2599,17 +2599,17 @@ namespace ts {
// File-level diagnostics reported by the parser (includes diagnostics about /// references
// as well as code diagnostics).
/* @internal */ parseDiagnostics: Diagnostic[];
/* @internal */ parseDiagnostics: DiagnosticWithLocation[];
// File-level diagnostics reported by the binder.
/* @internal */ bindDiagnostics: Diagnostic[];
/* @internal */ bindSuggestionDiagnostics?: Diagnostic[];
/* @internal */ bindDiagnostics: DiagnosticWithLocation[];
/* @internal */ bindSuggestionDiagnostics?: DiagnosticWithLocation[];
// File-level JSDoc diagnostics reported by the JSDoc parser
/* @internal */ jsDocDiagnostics?: Diagnostic[];
/* @internal */ jsDocDiagnostics?: DiagnosticWithLocation[];
// Stores additional file-level diagnostics reported by the program
/* @internal */ additionalSyntacticDiagnostics?: ReadonlyArray<Diagnostic>;
/* @internal */ additionalSyntacticDiagnostics?: ReadonlyArray<DiagnosticWithLocation>;
// Stores a line map for the file.
// This field should never be used directly to obtain line map, use getLineMap function instead.
@ -2747,9 +2747,10 @@ namespace ts {
getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
/** The first time this is called, it will return global diagnostics (no location). */
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
/**
@ -3070,7 +3071,7 @@ namespace ts {
* Does *not* get *all* suggestion diagnostics, just the ones that were convenient to report in the checker.
* Others are added in computeSuggestionDiagnostics.
*/
/* @internal */ getSuggestionDiagnostics(file: SourceFile): ReadonlyArray<Diagnostic>;
/* @internal */ getSuggestionDiagnostics(file: SourceFile): ReadonlyArray<DiagnosticWithLocation>;
/**
* Depending on the operation performed, it may be appropriate to throw away the checker
@ -4228,6 +4229,11 @@ namespace ts {
code: number;
source?: string;
}
export interface DiagnosticWithLocation extends Diagnostic {
file: SourceFile;
start: number;
length: number;
}
export enum DiagnosticCategory {
Warning,
@ -5084,7 +5090,7 @@ namespace ts {
*/
onEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
/* @internal */ addDiagnostic(diag: Diagnostic): void;
/* @internal */ addDiagnostic(diag: DiagnosticWithLocation): void;
}
export interface TransformationResult<T extends Node> {
@ -5092,7 +5098,7 @@ namespace ts {
transformed: T[];
/** Gets diagnostics for the transformation. */
diagnostics?: Diagnostic[];
diagnostics?: DiagnosticWithLocation[];
/**
* Gets a substitute for a node, if one is available; otherwise, returns the original node.
@ -5310,7 +5316,8 @@ namespace ts {
// If fileName is provided, gets all the diagnostics associated with that file name.
// Otherwise, returns all the diagnostics (global and file associated) in this collection.
getDiagnostics(fileName?: string): Diagnostic[];
getDiagnostics(fileName: string): DiagnosticWithLocation[];
getDiagnostics(): Diagnostic[];
reattachFileDiagnostics(newFile: SourceFile): void;
}

View File

@ -603,7 +603,7 @@ namespace ts {
}
}
export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic {
export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation {
const sourceFile = getSourceFileOfNode(node);
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3);
}
@ -613,17 +613,17 @@ namespace ts {
return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic {
export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation {
const span = getErrorSpanForNode(sourceFile, node);
return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeSpan(sourceFile: SourceFile, startNode: Node, endNode: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic {
export function createDiagnosticForNodeSpan(sourceFile: SourceFile, startNode: Node, endNode: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation {
const start = skipTrivia(sourceFile.text, startNode.pos);
return createFileDiagnostic(sourceFile, start, endNode.end - start, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic {
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): DiagnosticWithLocation {
const sourceFile = getSourceFileOfNode(node);
const span = getErrorSpanForNode(sourceFile, node);
return {
@ -2645,7 +2645,7 @@ namespace ts {
export function createDiagnosticCollection(): DiagnosticCollection {
let nonFileDiagnostics = [] as SortedArray<Diagnostic>;
const filesWithDiagnostics = [] as SortedArray<string>;
const fileDiagnostics = createMap<SortedArray<Diagnostic>>();
const fileDiagnostics = createMap<SortedArray<DiagnosticWithLocation>>();
let hasReadNonFileDiagnostics = false;
return {
@ -2664,8 +2664,8 @@ namespace ts {
if (diagnostic.file) {
diagnostics = fileDiagnostics.get(diagnostic.file.fileName);
if (!diagnostics) {
diagnostics = [] as SortedArray<Diagnostic>;
fileDiagnostics.set(diagnostic.file.fileName, diagnostics);
diagnostics = [] as SortedArray<DiagnosticWithLocation>;
fileDiagnostics.set(diagnostic.file.fileName, diagnostics as SortedArray<DiagnosticWithLocation>);
insertSorted(filesWithDiagnostics, diagnostic.file.fileName, compareStringsCaseSensitive);
}
}
@ -2687,12 +2687,14 @@ namespace ts {
return nonFileDiagnostics;
}
function getDiagnostics(fileName: string): DiagnosticWithLocation[];
function getDiagnostics(): Diagnostic[];
function getDiagnostics(fileName?: string): Diagnostic[] {
if (fileName) {
return fileDiagnostics.get(fileName) || [];
}
const fileDiags = flatMap(filesWithDiagnostics, f => fileDiagnostics.get(f));
const fileDiags: Diagnostic[] = flatMap(filesWithDiagnostics, f => fileDiagnostics.get(f));
if (!nonFileDiagnostics.length) {
return fileDiags;
}

View File

@ -1406,7 +1406,7 @@ namespace Harness {
const dupeCase = ts.createMap<number>();
for (const inputFile of inputFiles.filter(f => f.content !== undefined)) {
// Filter down to the errors in the file
const fileErrors = diagnostics.filter(e => {
const fileErrors = diagnostics.filter((e): e is ts.DiagnosticWithLocation => {
const errFn = e.file;
return errFn && utils.removeTestPathPrefixes(errFn.fileName) === utils.removeTestPathPrefixes(inputFile.unitName);
});

View File

@ -398,13 +398,13 @@ namespace Harness.LanguageService {
cleanupSemanticCache(): void {
this.shim.cleanupSemanticCache();
}
getSyntacticDiagnostics(fileName: string): ts.Diagnostic[] {
getSyntacticDiagnostics(fileName: string): ts.DiagnosticWithLocation[] {
return unwrapJSONCallResult(this.shim.getSyntacticDiagnostics(fileName));
}
getSemanticDiagnostics(fileName: string): ts.Diagnostic[] {
getSemanticDiagnostics(fileName: string): ts.DiagnosticWithLocation[] {
return unwrapJSONCallResult(this.shim.getSemanticDiagnostics(fileName));
}
getSuggestionDiagnostics(fileName: string): ts.Diagnostic[] {
getSuggestionDiagnostics(fileName: string): ts.DiagnosticWithLocation[] {
return unwrapJSONCallResult(this.shim.getSuggestionDiagnostics(fileName));
}
getCompilerOptionsDiagnostics(): ts.Diagnostic[] {

View File

@ -154,7 +154,7 @@ namespace project {
const configParseResult = ts.parseJsonSourceFileConfigFileContent(result, configParseHost, ts.getDirectoryPath(configFileName), this.compilerOptions);
inputFiles = configParseResult.fileNames;
this.compilerOptions = configParseResult.options;
errors = result.parseDiagnostics.concat(configParseResult.errors);
errors = [...result.parseDiagnostics, ...configParseResult.errors];
}
const compilerHost = new ProjectCompilerHost(this.sys, this.compilerOptions, this.testCaseJustName, this.testCase, moduleKind);

View File

@ -346,21 +346,21 @@ namespace ts.server {
return notImplemented();
}
getSyntacticDiagnostics(file: string): Diagnostic[] {
getSyntacticDiagnostics(file: string): DiagnosticWithLocation[] {
return this.getDiagnostics(file, CommandNames.SyntacticDiagnosticsSync);
}
getSemanticDiagnostics(file: string): Diagnostic[] {
getSemanticDiagnostics(file: string): DiagnosticWithLocation[] {
return this.getDiagnostics(file, CommandNames.SemanticDiagnosticsSync);
}
getSuggestionDiagnostics(file: string): Diagnostic[] {
getSuggestionDiagnostics(file: string): DiagnosticWithLocation[] {
return this.getDiagnostics(file, CommandNames.SuggestionDiagnosticsSync);
}
private getDiagnostics(file: string, command: CommandNames): Diagnostic[] {
private getDiagnostics(file: string, command: CommandNames): DiagnosticWithLocation[] {
const request = this.processRequest<protocol.SyntacticDiagnosticsSyncRequest | protocol.SemanticDiagnosticsSyncRequest | protocol.SuggestionDiagnosticsSyncRequest>(command, { file, includeLinePosition: true });
const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse | protocol.SemanticDiagnosticsSyncResponse | protocol.SuggestionDiagnosticsSyncResponse>(request);
return (<protocol.DiagnosticWithLinePosition[]>response.body).map((entry): Diagnostic => {
return (<protocol.DiagnosticWithLinePosition[]>response.body).map((entry): DiagnosticWithLocation => {
const category = firstDefined(Object.keys(DiagnosticCategory), id =>
isString(id) && entry.category === id.toLowerCase() ? (<any>DiagnosticCategory)[id] : undefined);
return {

View File

@ -1329,7 +1329,7 @@ namespace ts.server {
if (!result.endOfFileToken) {
result.endOfFileToken = <EndOfFileToken>{ kind: SyntaxKind.EndOfFileToken };
}
const errors = result.parseDiagnostics;
const errors = result.parseDiagnostics as Diagnostic[];
const parsedCommandLine = parseJsonSourceFileConfigFileContent(
result,
cachedDirectoryStructureHost,

View File

@ -79,17 +79,17 @@ namespace ts {
return { fileName, textChanges };
}
export function codeFixAll(context: CodeFixAllContext, errorCodes: number[], use: (changes: textChanges.ChangeTracker, error: Diagnostic, commands: Push<CodeActionCommand>) => void): CombinedCodeActions {
export function codeFixAll(context: CodeFixAllContext, errorCodes: number[], use: (changes: textChanges.ChangeTracker, error: DiagnosticWithLocation, commands: Push<CodeActionCommand>) => void): CombinedCodeActions {
const commands: CodeActionCommand[] = [];
const changes = textChanges.ChangeTracker.with(context, t =>
eachDiagnostic(context, errorCodes, diag => use(t, diag, commands)));
return createCombinedCodeActions(changes, commands.length === 0 ? undefined : commands);
}
function eachDiagnostic({ program, sourceFile }: CodeFixAllContext, errorCodes: number[], cb: (diag: Diagnostic) => void): void {
function eachDiagnostic({ program, sourceFile }: CodeFixAllContext, errorCodes: number[], cb: (diag: DiagnosticWithLocation) => void): void {
for (const diag of program.getSemanticDiagnostics(sourceFile).concat(computeSuggestionDiagnostics(sourceFile, program))) {
if (contains(errorCodes, diag.code)) {
cb(diag);
cb(diag as DiagnosticWithLocation);
}
}
}

View File

@ -9,7 +9,7 @@ namespace ts.codefix {
return [createCodeFixAction(fixId, changes, Diagnostics.Call_decorator_expression, fixId, Diagnostics.Add_to_all_uncalled_decorators)];
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file!, diag.start!)),
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)),
});
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) {

View File

@ -12,8 +12,8 @@ namespace ts.codefix {
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const decl = getDeclaration(diag.file!, diag.start!);
if (decl) doChange(changes, diag.file!, decl);
const decl = getDeclaration(diag.file, diag.start);
if (decl) doChange(changes, diag.file, decl);
}),
});

View File

@ -38,8 +38,8 @@ namespace ts.codefix {
getAllCodeActions: context => {
const seenLines = createMap<true>();
return codeFixAll(context, errorCodes, (changes, diag) => {
if (textChanges.isValidLocationToAddComment(diag.file!, diag.start!)) {
makeChange(changes, diag.file!, diag.start!, seenLines);
if (textChanges.isValidLocationToAddComment(diag.file, diag.start)) {
makeChange(changes, diag.file, diag.start, seenLines);
}
});
},

View File

@ -23,7 +23,7 @@ namespace ts.codefix {
const seenNames = createMap<true>();
return codeFixAll(context, errorCodes, (changes, diag) => {
const { program, preferences } = context;
const info = getInfo(diag.file!, diag.start!, program.getTypeChecker());
const info = getInfo(diag.file, diag.start, program.getTypeChecker());
if (!info) return;
const { classDeclaration, classDeclarationSourceFile, inJs, makeStatic, token, call } = info;
if (!addToSeen(seenNames, token.text)) {

View File

@ -17,7 +17,7 @@ namespace ts.codefix {
getAllCodeActions: context => {
const seenClassDeclarations = createMap<true>();
return codeFixAll(context, errorCodes, (changes, diag) => {
const classDeclaration = getClass(diag.file!, diag.start!);
const classDeclaration = getClass(diag.file, diag.start);
if (addToSeen(seenClassDeclarations, getNodeId(classDeclaration))) {
addMissingMembers(classDeclaration, context.sourceFile, context.program.getTypeChecker(), changes, context.preferences);
}

View File

@ -18,10 +18,10 @@ namespace ts.codefix {
getAllCodeActions(context) {
const seenClassDeclarations = createMap<true>();
return codeFixAll(context, errorCodes, (changes, diag) => {
const classDeclaration = getClass(diag.file!, diag.start!);
const classDeclaration = getClass(diag.file, diag.start);
if (addToSeen(seenClassDeclarations, getNodeId(classDeclaration))) {
for (const implementedTypeNode of getClassImplementsHeritageClauseElements(classDeclaration)) {
addMissingDeclarations(context.program.getTypeChecker(), implementedTypeNode, diag.file!, classDeclaration, changes, context.preferences);
addMissingDeclarations(context.program.getTypeChecker(), implementedTypeNode, diag.file, classDeclaration, changes, context.preferences);
}
}
});

View File

@ -17,7 +17,7 @@ namespace ts.codefix {
const { sourceFile } = context;
const seenClasses = createMap<true>(); // Ensure we only do this once per class.
return codeFixAll(context, errorCodes, (changes, diag) => {
const nodes = getNodes(diag.file!, diag.start!);
const nodes = getNodes(diag.file, diag.start);
if (!nodes) return;
const { constructor, superCall } = nodes;
if (addToSeen(seenClasses, getNodeId(constructor.parent))) {

View File

@ -12,7 +12,7 @@ namespace ts.codefix {
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) =>
doChange(changes, context.sourceFile, getNode(diag.file, diag.start!))),
doChange(changes, context.sourceFile, getNode(diag.file, diag.start))),
});
function getNode(sourceFile: SourceFile, pos: number): ConstructorDeclaration {

View File

@ -14,7 +14,7 @@ namespace ts.codefix {
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const nodes = getNodes(diag.file, diag.start!);
const nodes = getNodes(diag.file, diag.start);
if (nodes) doChanges(changes, diag.file, nodes.extendsToken, nodes.heritageClauses);
}),
});

View File

@ -19,7 +19,7 @@ namespace ts.codefix {
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
doChange(changes, context.sourceFile, getInfo(diag.file, diag.start!, diag.code));
doChange(changes, context.sourceFile, getInfo(diag.file, diag.start, diag.code));
}),
});

View File

@ -19,7 +19,7 @@ namespace ts.codefix {
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const info = getInfo(diag.file!, diag.start!, context);
const info = getInfo(diag.file, diag.start, context);
const { target } = context.host.getCompilationSettings();
if (info) doChange(changes, context.sourceFile, info.node, info.suggestion, target);
}),

View File

@ -53,7 +53,7 @@ namespace ts.codefix {
return codeFixAll(context, errorCodes, (changes, diag) => {
const { sourceFile } = context;
const startToken = getTokenAtPosition(sourceFile, diag.start, /*includeJsDocComment*/ false);
const token = findPrecedingToken(textSpanEnd(diag), diag.file!);
const token = findPrecedingToken(textSpanEnd(diag), diag.file);
switch (context.fixId) {
case fixIdPrefix:
if (isIdentifier(token) && canPrefix(token)) {
@ -62,7 +62,7 @@ namespace ts.codefix {
break;
case fixIdDelete:
// Ignore if this range was already deleted.
if (deleted.some(d => rangeContainsPosition(d, diag.start!))) break;
if (deleted.some(d => rangeContainsPosition(d, diag.start))) break;
const importDecl = tryGetFullImport(startToken);
if (importDecl) {

View File

@ -13,8 +13,8 @@ namespace ts.codefix {
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const info = getInfo(diag.file!, diag.start!);
if (info) doChange(changes, diag.file!, info);
const info = getInfo(diag.file, diag.start);
if (info) doChange(changes, diag.file, info);
}),
});

View File

@ -228,7 +228,7 @@ namespace ts.formatting {
* This function will return a predicate that for a given text range will tell
* if there are any parse errors that overlap with the range.
*/
function prepareRangeContainsErrorFunction(errors: Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean {
function prepareRangeContainsErrorFunction(errors: ReadonlyArray<Diagnostic>, originalRange: TextRange): (r: TextRange) => boolean {
if (!errors.length) {
return rangeHasNoErrors;
}

View File

@ -545,10 +545,10 @@ namespace ts {
public referencedFiles: FileReference[];
public typeReferenceDirectives: FileReference[];
public syntacticDiagnostics: Diagnostic[];
public parseDiagnostics: Diagnostic[];
public bindDiagnostics: Diagnostic[];
public bindSuggestionDiagnostics?: Diagnostic[];
public syntacticDiagnostics: DiagnosticWithLocation[];
public parseDiagnostics: DiagnosticWithLocation[];
public bindDiagnostics: DiagnosticWithLocation[];
public bindSuggestionDiagnostics?: DiagnosticWithLocation[];
public isDeclarationFile: boolean;
public isDefaultLib: boolean;
@ -1377,7 +1377,7 @@ namespace ts {
}
/// Diagnostics
function getSyntacticDiagnostics(fileName: string): Diagnostic[] {
function getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[] {
synchronizeHostData();
return program.getSyntacticDiagnostics(getValidSourceFile(fileName), cancellationToken).slice();
@ -1405,7 +1405,7 @@ namespace ts {
return [...semanticDiagnostics, ...declarationDiagnostics];
}
function getSuggestionDiagnostics(fileName: string): Diagnostic[] {
function getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[] {
synchronizeHostData();
return computeSuggestionDiagnostics(getValidSourceFile(fileName), program);
}

View File

@ -1147,7 +1147,7 @@ namespace ts {
typeAcquisition: configFile.typeAcquisition,
files: configFile.fileNames,
raw: configFile.raw,
errors: realizeDiagnostics(result.parseDiagnostics.concat(configFile.errors), "\r\n")
errors: realizeDiagnostics([...result.parseDiagnostics, ...configFile.errors], "\r\n")
};
});
}

View File

@ -1,9 +1,9 @@
/* @internal */
namespace ts {
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program): Diagnostic[] {
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program): DiagnosticWithLocation[] {
program.getSemanticDiagnostics(sourceFile);
const checker = program.getDiagnosticsProducingTypeChecker();
const diags: Diagnostic[] = [];
const diags: DiagnosticWithLocation[] = [];
if (sourceFile.commonJsModuleIndicator &&
(programContainsEs6Modules(program) || compilerOptionsIndicateEs6Modules(program.getCompilerOptions())) &&

View File

@ -6,7 +6,7 @@ namespace ts {
* @param compilerOptions Optional compiler options.
*/
export function transform<T extends Node>(source: T | T[], transformers: TransformerFactory<T>[], compilerOptions?: CompilerOptions) {
const diagnostics: Diagnostic[] = [];
const diagnostics: DiagnosticWithLocation[] = [];
compilerOptions = fixupCompilerOptions(compilerOptions, diagnostics);
const nodes = isArray(source) ? source : [source];
const result = transformNodes(/*resolver*/ undefined, /*emitHost*/ undefined, compilerOptions, nodes, transformers, /*allowDtsFiles*/ true);

View File

@ -249,9 +249,10 @@ namespace ts {
export interface LanguageService {
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): Diagnostic[];
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
/** The first time this is called, it will return global diagnostics (no location). */
getSemanticDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[];
// TODO: Rename this to getProgramDiagnostics to better indicate that these are any
// diagnostics present for the program level, and not just 'options' diagnostics.

View File

@ -1734,9 +1734,10 @@ declare namespace ts {
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
/** The first time this is called, it will return global diagnostics (no location). */
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
/**
* Gets a type checker that can be used to semantically analyze source files in the program.
@ -2359,6 +2360,11 @@ declare namespace ts {
code: number;
source?: string;
}
interface DiagnosticWithLocation extends Diagnostic {
file: SourceFile;
start: number;
length: number;
}
enum DiagnosticCategory {
Warning = 0,
Error = 1,
@ -2754,7 +2760,7 @@ declare namespace ts {
/** Gets the transformed source files. */
transformed: T[];
/** Gets diagnostics for the transformation. */
diagnostics?: Diagnostic[];
diagnostics?: DiagnosticWithLocation[];
/**
* Gets a substitute for a node, if one is available; otherwise, returns the original node.
*
@ -2960,7 +2966,7 @@ declare namespace ts {
}
declare namespace ts {
function isExternalModuleNameRelative(moduleName: string): boolean;
function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): Diagnostic[];
function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: ReadonlyArray<T>): T[];
}
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
@ -4497,9 +4503,10 @@ declare namespace ts {
}
interface LanguageService {
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): Diagnostic[];
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
/** The first time this is called, it will return global diagnostics (no location). */
getSemanticDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[];
getCompilerOptionsDiagnostics(): Diagnostic[];
/**
* @deprecated Use getEncodedSyntacticClassifications instead.

View File

@ -1734,9 +1734,10 @@ declare namespace ts {
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
/** The first time this is called, it will return global diagnostics (no location). */
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
/**
* Gets a type checker that can be used to semantically analyze source files in the program.
@ -2359,6 +2360,11 @@ declare namespace ts {
code: number;
source?: string;
}
interface DiagnosticWithLocation extends Diagnostic {
file: SourceFile;
start: number;
length: number;
}
enum DiagnosticCategory {
Warning = 0,
Error = 1,
@ -2754,7 +2760,7 @@ declare namespace ts {
/** Gets the transformed source files. */
transformed: T[];
/** Gets diagnostics for the transformation. */
diagnostics?: Diagnostic[];
diagnostics?: DiagnosticWithLocation[];
/**
* Gets a substitute for a node, if one is available; otherwise, returns the original node.
*
@ -2960,7 +2966,7 @@ declare namespace ts {
}
declare namespace ts {
function isExternalModuleNameRelative(moduleName: string): boolean;
function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): Diagnostic[];
function sortAndDeduplicateDiagnostics<T extends Diagnostic>(diagnostics: ReadonlyArray<T>): T[];
}
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
@ -4497,9 +4503,10 @@ declare namespace ts {
}
interface LanguageService {
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): Diagnostic[];
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
/** The first time this is called, it will return global diagnostics (no location). */
getSemanticDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): Diagnostic[];
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[];
getCompilerOptionsDiagnostics(): Diagnostic[];
/**
* @deprecated Use getEncodedSyntacticClassifications instead.