mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Merge pull request #3561 from Microsoft/cancellableDiagnostics
Make it possible to cancel requests to get diagnostics.
This commit is contained in:
commit
9b2d44a676
@ -22,6 +22,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
|
||||
// Cancellation that controls whether or not we can cancel in the middle of type checking.
|
||||
// In general cancelling is *not* safe for the type checker. We might be in the middle of
|
||||
// computing something, and we will leave our internals in an inconsistent state. Callers
|
||||
// who set the cancellation token should catch if a cancellation exception occurs, and
|
||||
// should throw away and create a new TypeChecker.
|
||||
//
|
||||
// Currently we only support setting the cancellation token when getting diagnostics. This
|
||||
// is because diagnostics can be quite expensive, and we want to allow hosts to bail out if
|
||||
// they no longer need the information (for example, if the user started editing again).
|
||||
let cancellationToken: CancellationToken;
|
||||
|
||||
let Symbol = objectAllocator.getSymbolConstructor();
|
||||
let Type = objectAllocator.getTypeConstructor();
|
||||
let Signature = objectAllocator.getSignatureConstructor();
|
||||
@ -194,10 +205,10 @@ namespace ts {
|
||||
|
||||
return checker;
|
||||
|
||||
function getEmitResolver(sourceFile?: SourceFile) {
|
||||
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
|
||||
// Ensure we have all the type information in place for this file so that all the
|
||||
// emitter questions of this resolver will return the right information.
|
||||
getDiagnostics(sourceFile);
|
||||
getDiagnostics(sourceFile, cancellationToken);
|
||||
return emitResolver;
|
||||
}
|
||||
|
||||
@ -13028,8 +13039,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkSourceElement(node: Node): void {
|
||||
if (!node) return;
|
||||
switch (node.kind) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
let kind = node.kind;
|
||||
if (cancellationToken) {
|
||||
// Only bother checking on a few construct kinds. We don't want to be excessivly
|
||||
// hitting the cancellation token on every node we check.
|
||||
switch (kind) {
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
return checkTypeParameter(<TypeParameterDeclaration>node);
|
||||
case SyntaxKind.Parameter:
|
||||
@ -13305,7 +13332,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
|
||||
function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken): Diagnostic[] {
|
||||
try {
|
||||
// Record the cancellation token so it can be checked later on during checkSourceElement.
|
||||
// Do this in a finally block so we can ensure that it gets reset back to nothing after
|
||||
// this call is done.
|
||||
cancellationToken = ct;
|
||||
return getDiagnosticsWorker(sourceFile);
|
||||
}
|
||||
finally {
|
||||
cancellationToken = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function getDiagnosticsWorker(sourceFile: SourceFile): Diagnostic[] {
|
||||
throwIfNonDiagnosticsProducing();
|
||||
if (sourceFile) {
|
||||
checkSourceFile(sourceFile);
|
||||
|
||||
@ -805,4 +805,4 @@ namespace ts {
|
||||
Debug.assert(false, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,14 +104,14 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile): Diagnostic[] {
|
||||
let diagnostics = program.getOptionsDiagnostics().concat(
|
||||
program.getSyntacticDiagnostics(sourceFile),
|
||||
program.getGlobalDiagnostics(),
|
||||
program.getSemanticDiagnostics(sourceFile));
|
||||
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[] {
|
||||
let diagnostics = program.getOptionsDiagnostics(cancellationToken).concat(
|
||||
program.getSyntacticDiagnostics(sourceFile, cancellationToken),
|
||||
program.getGlobalDiagnostics(cancellationToken),
|
||||
program.getSemanticDiagnostics(sourceFile, cancellationToken));
|
||||
|
||||
if (program.getCompilerOptions().declaration) {
|
||||
diagnostics.concat(program.getDeclarationDiagnostics(sourceFile));
|
||||
diagnostics.concat(program.getDeclarationDiagnostics(sourceFile, cancellationToken));
|
||||
}
|
||||
|
||||
return sortAndDeduplicateDiagnostics(diagnostics);
|
||||
@ -233,10 +233,15 @@ namespace ts {
|
||||
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ false));
|
||||
}
|
||||
|
||||
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback): EmitResult {
|
||||
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult {
|
||||
return runWithCancellationToken(() => emitWorker(this, sourceFile, writeFileCallback, cancellationToken));
|
||||
}
|
||||
|
||||
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken): EmitResult {
|
||||
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
|
||||
// immediately bail out.
|
||||
if (options.noEmitOnError && getPreEmitDiagnostics(this).length > 0) {
|
||||
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
|
||||
// get any preEmit diagnostics, not just the ones
|
||||
if (options.noEmitOnError && getPreEmitDiagnostics(program, /*sourceFile:*/ undefined, cancellationToken).length > 0) {
|
||||
return { diagnostics: [], sourceMaps: undefined, emitSkipped: true };
|
||||
}
|
||||
|
||||
@ -265,53 +270,86 @@ namespace ts {
|
||||
return filesByName.get(fileName);
|
||||
}
|
||||
|
||||
function getDiagnosticsHelper(sourceFile: SourceFile, getDiagnostics: (sourceFile: SourceFile) => Diagnostic[]): Diagnostic[] {
|
||||
function getDiagnosticsHelper(
|
||||
sourceFile: SourceFile,
|
||||
getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken) => Diagnostic[],
|
||||
cancellationToken: CancellationToken): Diagnostic[] {
|
||||
if (sourceFile) {
|
||||
return getDiagnostics(sourceFile);
|
||||
return getDiagnostics(sourceFile, cancellationToken);
|
||||
}
|
||||
|
||||
let allDiagnostics: Diagnostic[] = [];
|
||||
forEach(program.getSourceFiles(), sourceFile => {
|
||||
addRange(allDiagnostics, getDiagnostics(sourceFile));
|
||||
if (cancellationToken) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
}
|
||||
addRange(allDiagnostics, getDiagnostics(sourceFile, cancellationToken));
|
||||
});
|
||||
|
||||
return sortAndDeduplicateDiagnostics(allDiagnostics);
|
||||
}
|
||||
|
||||
function getSyntacticDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
|
||||
return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile);
|
||||
function getSyntacticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken);
|
||||
}
|
||||
|
||||
function getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
|
||||
return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile);
|
||||
function getSemanticDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken);
|
||||
}
|
||||
|
||||
function getDeclarationDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
|
||||
return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile);
|
||||
function getDeclarationDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return getDiagnosticsHelper(sourceFile, getDeclarationDiagnosticsForFile, cancellationToken);
|
||||
}
|
||||
|
||||
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
|
||||
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return sourceFile.parseDiagnostics;
|
||||
}
|
||||
|
||||
function getSemanticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
|
||||
let typeChecker = getDiagnosticsProducingTypeChecker();
|
||||
function runWithCancellationToken<T>(func: () => T): T {
|
||||
try {
|
||||
return func();
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof OperationCanceledException) {
|
||||
// We were canceled while performing the operation. Because our type checker
|
||||
// might be a bad state, we need to throw it away.
|
||||
//
|
||||
// Note: we are overly agressive here. We do not actually *have* to throw away
|
||||
// the "noDiagnosticsTypeChecker". However, for simplicity, i'd like to keep
|
||||
// the lifetimes of these two TypeCheckers the same. Also, we generally only
|
||||
// cancel when the user has made a change anyways. And, in that case, we (the
|
||||
// program instance) will get thrown away anyways. So trying to keep one of
|
||||
// these type checkers alive doesn't serve much purpose.
|
||||
noDiagnosticsTypeChecker = undefined;
|
||||
diagnosticsProducingTypeChecker = undefined;
|
||||
}
|
||||
|
||||
Debug.assert(!!sourceFile.bindDiagnostics);
|
||||
let bindDiagnostics = sourceFile.bindDiagnostics;
|
||||
let checkDiagnostics = typeChecker.getDiagnostics(sourceFile);
|
||||
let programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
|
||||
|
||||
return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
|
||||
if (!isDeclarationFile(sourceFile)) {
|
||||
let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile);
|
||||
// Don't actually write any files since we're just getting diagnostics.
|
||||
var writeFile: WriteFileCallback = () => { };
|
||||
return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile);
|
||||
}
|
||||
function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return runWithCancellationToken(() => {
|
||||
let typeChecker = getDiagnosticsProducingTypeChecker();
|
||||
|
||||
Debug.assert(!!sourceFile.bindDiagnostics);
|
||||
let bindDiagnostics = sourceFile.bindDiagnostics;
|
||||
let checkDiagnostics = typeChecker.getDiagnostics(sourceFile, cancellationToken);
|
||||
let programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
|
||||
|
||||
return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics);
|
||||
});
|
||||
}
|
||||
|
||||
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
||||
return runWithCancellationToken(() => {
|
||||
if (!isDeclarationFile(sourceFile)) {
|
||||
let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken);
|
||||
// Don't actually write any files since we're just getting diagnostics.
|
||||
var writeFile: WriteFileCallback = () => { };
|
||||
return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getOptionsDiagnostics(): Diagnostic[] {
|
||||
|
||||
@ -1290,6 +1290,15 @@ namespace ts {
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void): void;
|
||||
}
|
||||
|
||||
export class OperationCanceledException { }
|
||||
|
||||
export interface CancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
|
||||
/** @throws OperationCanceledException if isCancellationRequested is true */
|
||||
throwIfCancellationRequested(): void;
|
||||
}
|
||||
|
||||
export interface Program extends ScriptReferenceHost {
|
||||
/**
|
||||
* Get a list of files in the program
|
||||
@ -1306,13 +1315,13 @@ namespace ts {
|
||||
* used for writing the JavaScript and declaration files. Otherwise, the writeFile parameter
|
||||
* will be invoked when writing the JavaScript and declaration files.
|
||||
*/
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
|
||||
|
||||
getOptionsDiagnostics(): Diagnostic[];
|
||||
getGlobalDiagnostics(): Diagnostic[];
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile): Diagnostic[];
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[];
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile): Diagnostic[];
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
|
||||
/**
|
||||
* Gets a type checker that can be used to semantically analyze source fils in the program.
|
||||
@ -1423,9 +1432,9 @@ namespace ts {
|
||||
getJsxIntrinsicTagNames(): Symbol[];
|
||||
|
||||
// Should not be called directly. Should only be accessed through the Program instance.
|
||||
/* @internal */ getDiagnostics(sourceFile?: SourceFile): Diagnostic[];
|
||||
/* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
/* @internal */ getGlobalDiagnostics(): Diagnostic[];
|
||||
/* @internal */ getEmitResolver(sourceFile?: SourceFile): EmitResolver;
|
||||
/* @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken): EmitResolver;
|
||||
|
||||
/* @internal */ getNodeCount(): number;
|
||||
/* @internal */ getIdentifierCount(): number;
|
||||
@ -2178,14 +2187,9 @@ namespace ts {
|
||||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
export interface CancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
}
|
||||
|
||||
export interface CompilerHost {
|
||||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getCancellationToken? (): CancellationToken;
|
||||
writeFile: WriteFileCallback;
|
||||
getCurrentDirectory(): string;
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
|
||||
@ -190,14 +190,14 @@ module FourSlash {
|
||||
return "\nMarker: " + currentTestState.lastKnownMarker + "\nChecking: " + msg + "\n\n";
|
||||
}
|
||||
|
||||
export class TestCancellationToken implements ts.CancellationToken {
|
||||
export class TestCancellationToken implements ts.HostCancellationToken {
|
||||
// 0 - cancelled
|
||||
// >0 - not cancelled
|
||||
// <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled
|
||||
private static NotCancelled: number = -1;
|
||||
private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCancelled;
|
||||
public isCancellationRequested(): boolean {
|
||||
private static NotCanceled: number = -1;
|
||||
private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCanceled;
|
||||
|
||||
public isCancellationRequested(): boolean {
|
||||
if (this.numberOfCallsBeforeCancellation < 0) {
|
||||
return false;
|
||||
}
|
||||
@ -216,7 +216,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
public resetCancelled(): void {
|
||||
this.numberOfCallsBeforeCancellation = TestCancellationToken.NotCancelled;
|
||||
this.numberOfCallsBeforeCancellation = TestCancellationToken.NotCanceled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -103,14 +103,11 @@ module Harness.LanguageService {
|
||||
}
|
||||
}
|
||||
|
||||
class CancellationToken {
|
||||
public static None: CancellationToken = new CancellationToken(null);
|
||||
|
||||
constructor(private cancellationToken: ts.CancellationToken) {
|
||||
}
|
||||
class DefaultHostCancellationToken implements ts.HostCancellationToken {
|
||||
public static Instance = new DefaultHostCancellationToken();
|
||||
|
||||
public isCancellationRequested() {
|
||||
return this.cancellationToken && this.cancellationToken.isCancellationRequested();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,8 +121,8 @@ module Harness.LanguageService {
|
||||
export class LanguageServiceAdapterHost {
|
||||
protected fileNameToScript: ts.Map<ScriptInfo> = {};
|
||||
|
||||
constructor(protected cancellationToken: ts.CancellationToken = CancellationToken.None,
|
||||
protected settings = ts.getDefaultCompilerOptions()) {
|
||||
constructor(protected cancellationToken = DefaultHostCancellationToken.Instance,
|
||||
protected settings = ts.getDefaultCompilerOptions()) {
|
||||
}
|
||||
|
||||
public getNewLine(): string {
|
||||
@ -173,8 +170,8 @@ module Harness.LanguageService {
|
||||
|
||||
/// Native adapter
|
||||
class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost {
|
||||
getCompilationSettings(): ts.CompilerOptions { return this.settings; }
|
||||
getCancellationToken(): ts.CancellationToken { return this.cancellationToken; }
|
||||
getCompilationSettings() { return this.settings; }
|
||||
getCancellationToken() { return this.cancellationToken; }
|
||||
getCurrentDirectory(): string { return ""; }
|
||||
getDefaultLibFileName(): string { return ""; }
|
||||
getScriptFileNames(): string[] { return this.getFilenames(); }
|
||||
@ -194,7 +191,7 @@ module Harness.LanguageService {
|
||||
|
||||
export class NativeLanugageServiceAdapter implements LanguageServiceAdapter {
|
||||
private host: NativeLanguageServiceHost;
|
||||
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
|
||||
constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) {
|
||||
this.host = new NativeLanguageServiceHost(cancellationToken, options);
|
||||
}
|
||||
getHost() { return this.host; }
|
||||
@ -206,7 +203,7 @@ module Harness.LanguageService {
|
||||
/// Shim adapter
|
||||
class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceShimHost, ts.CoreServicesShimHost {
|
||||
private nativeHost: NativeLanguageServiceHost;
|
||||
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
|
||||
constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) {
|
||||
super(cancellationToken, options);
|
||||
this.nativeHost = new NativeLanguageServiceHost(cancellationToken, options);
|
||||
}
|
||||
@ -218,7 +215,7 @@ module Harness.LanguageService {
|
||||
positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter { return this.nativeHost.positionToLineAndCharacter(fileName, position); }
|
||||
|
||||
getCompilationSettings(): string { return JSON.stringify(this.nativeHost.getCompilationSettings()); }
|
||||
getCancellationToken(): ts.CancellationToken { return this.nativeHost.getCancellationToken(); }
|
||||
getCancellationToken(): ts.HostCancellationToken { return this.nativeHost.getCancellationToken(); }
|
||||
getCurrentDirectory(): string { return this.nativeHost.getCurrentDirectory(); }
|
||||
getDefaultLibFileName(): string { return this.nativeHost.getDefaultLibFileName(); }
|
||||
getScriptFileNames(): string { return JSON.stringify(this.nativeHost.getScriptFileNames()); }
|
||||
@ -399,7 +396,7 @@ module Harness.LanguageService {
|
||||
export class ShimLanugageServiceAdapter implements LanguageServiceAdapter {
|
||||
private host: ShimLanguageServiceHost;
|
||||
private factory: ts.TypeScriptServicesFactory;
|
||||
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
|
||||
constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) {
|
||||
this.host = new ShimLanguageServiceHost(cancellationToken, options);
|
||||
this.factory = new TypeScript.Services.TypeScriptServicesFactory();
|
||||
}
|
||||
@ -446,7 +443,7 @@ module Harness.LanguageService {
|
||||
class SessionClientHost extends NativeLanguageServiceHost implements ts.server.SessionClientHost {
|
||||
private client: ts.server.SessionClient;
|
||||
|
||||
constructor(cancellationToken: ts.CancellationToken, settings: ts.CompilerOptions) {
|
||||
constructor(cancellationToken: ts.HostCancellationToken, settings: ts.CompilerOptions) {
|
||||
super(cancellationToken, settings);
|
||||
}
|
||||
|
||||
@ -575,7 +572,7 @@ module Harness.LanguageService {
|
||||
export class ServerLanugageServiceAdapter implements LanguageServiceAdapter {
|
||||
private host: SessionClientHost;
|
||||
private client: ts.server.SessionClient;
|
||||
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
|
||||
constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) {
|
||||
// This is the main host that tests use to direct tests
|
||||
var clientHost = new SessionClientHost(cancellationToken, options);
|
||||
var client = new ts.server.SessionClient(clientHost);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
namespace ts.NavigateTo {
|
||||
type RawNavigateToItem = { name: string; fileName: string; matchKind: PatternMatchKind; isCaseSensitive: boolean; declaration: Declaration };
|
||||
|
||||
export function getNavigateToItems(program: Program, cancellationToken: CancellationTokenObject, searchValue: string, maxResultCount: number): NavigateToItem[] {
|
||||
export function getNavigateToItems(program: Program, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number): NavigateToItem[] {
|
||||
let patternMatcher = createPatternMatcher(searchValue);
|
||||
let rawItems: RawNavigateToItem[] = [];
|
||||
|
||||
|
||||
@ -944,6 +944,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export interface HostCancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
}
|
||||
|
||||
//
|
||||
// Public interface of the host of a language service instance.
|
||||
//
|
||||
@ -955,7 +959,7 @@ namespace ts {
|
||||
getScriptVersion(fileName: string): string;
|
||||
getScriptSnapshot(fileName: string): IScriptSnapshot;
|
||||
getLocalizedDiagnosticMessages?(): any;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getCancellationToken?(): HostCancellationToken;
|
||||
getCurrentDirectory(): string;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
log? (s: string): void;
|
||||
@ -1615,25 +1619,6 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export class OperationCanceledException { }
|
||||
|
||||
export class CancellationTokenObject {
|
||||
public static None: CancellationTokenObject = new CancellationTokenObject(null)
|
||||
|
||||
constructor(private cancellationToken: CancellationToken) {
|
||||
}
|
||||
|
||||
public isCancellationRequested() {
|
||||
return this.cancellationToken && this.cancellationToken.isCancellationRequested();
|
||||
}
|
||||
|
||||
public throwIfCancellationRequested(): void {
|
||||
if (this.isCancellationRequested()) {
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache host information about scrip Should be refreshed
|
||||
// at each language service public entry point, since we don't know when
|
||||
// set of scripts handled by the host changes.
|
||||
@ -2400,6 +2385,21 @@ namespace ts {
|
||||
return ScriptElementKind.unknown;
|
||||
}
|
||||
|
||||
class CancellationTokenObject implements CancellationToken {
|
||||
constructor(private cancellationToken: HostCancellationToken) {
|
||||
}
|
||||
|
||||
public isCancellationRequested() {
|
||||
return this.cancellationToken && this.cancellationToken.isCancellationRequested();
|
||||
}
|
||||
|
||||
public throwIfCancellationRequested(): void {
|
||||
if (this.isCancellationRequested()) {
|
||||
throw new OperationCanceledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry = createDocumentRegistry()): LanguageService {
|
||||
let syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
|
||||
let ruleProvider: formatting.RulesProvider;
|
||||
@ -2604,7 +2604,7 @@ namespace ts {
|
||||
function getSyntacticDiagnostics(fileName: string) {
|
||||
synchronizeHostData();
|
||||
|
||||
return program.getSyntacticDiagnostics(getValidSourceFile(fileName));
|
||||
return program.getSyntacticDiagnostics(getValidSourceFile(fileName), cancellationToken);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2626,13 +2626,13 @@ namespace ts {
|
||||
// Only perform the action per file regardless of '-out' flag as LanguageServiceHost is expected to call this function per file.
|
||||
// Therefore only get diagnostics for given file.
|
||||
|
||||
let semanticDiagnostics = program.getSemanticDiagnostics(targetSourceFile);
|
||||
let semanticDiagnostics = program.getSemanticDiagnostics(targetSourceFile, cancellationToken);
|
||||
if (!program.getCompilerOptions().declaration) {
|
||||
return semanticDiagnostics;
|
||||
}
|
||||
|
||||
// If '-d' is enabled, check for emitter error. One example of emitter error is export class implements non-export interface
|
||||
let declarationDiagnostics = program.getDeclarationDiagnostics(targetSourceFile);
|
||||
let declarationDiagnostics = program.getDeclarationDiagnostics(targetSourceFile, cancellationToken);
|
||||
return concatenate(semanticDiagnostics, declarationDiagnostics);
|
||||
}
|
||||
|
||||
@ -2795,7 +2795,8 @@ namespace ts {
|
||||
|
||||
function getCompilerOptionsDiagnostics() {
|
||||
synchronizeHostData();
|
||||
return program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
|
||||
return program.getOptionsDiagnostics(cancellationToken).concat(
|
||||
program.getGlobalDiagnostics(cancellationToken));
|
||||
}
|
||||
|
||||
/// Completion
|
||||
@ -5815,7 +5816,7 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
let emitOutput = program.emit(sourceFile, writeFile);
|
||||
let emitOutput = program.emit(sourceFile, writeFile, cancellationToken);
|
||||
|
||||
return {
|
||||
outputFiles,
|
||||
|
||||
@ -51,7 +51,7 @@ namespace ts {
|
||||
getScriptVersion(fileName: string): string;
|
||||
getScriptSnapshot(fileName: string): ScriptSnapshotShim;
|
||||
getLocalizedDiagnosticMessages(): string;
|
||||
getCancellationToken(): CancellationToken;
|
||||
getCancellationToken(): HostCancellationToken;
|
||||
getCurrentDirectory(): string;
|
||||
getDefaultLibFileName(options: string): string;
|
||||
getNewLine?(): string;
|
||||
@ -326,7 +326,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
public getCancellationToken(): CancellationToken {
|
||||
public getCancellationToken(): HostCancellationToken {
|
||||
var hostCancellationToken = this.shimHost.getCancellationToken();
|
||||
return new ThrottledCancellationToken(hostCancellationToken);
|
||||
}
|
||||
@ -348,13 +348,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** A cancellation that throttles calls to the host */
|
||||
class ThrottledCancellationToken implements CancellationToken {
|
||||
class ThrottledCancellationToken implements HostCancellationToken {
|
||||
// Store when we last tried to cancel. Checking cancellation can be expensive (as we have
|
||||
// to marshall over to the host layer). So we only bother actually checking once enough
|
||||
// time has passed.
|
||||
private lastCancellationCheckTime = 0;
|
||||
|
||||
constructor(private hostCancellationToken: CancellationToken) {
|
||||
constructor(private hostCancellationToken: HostCancellationToken) {
|
||||
}
|
||||
|
||||
public isCancellationRequested(): boolean {
|
||||
|
||||
@ -178,7 +178,7 @@ namespace ts.SignatureHelp {
|
||||
argumentCount: number;
|
||||
}
|
||||
|
||||
export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationTokenObject): SignatureHelpItems {
|
||||
export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationToken): SignatureHelpItems {
|
||||
let typeChecker = program.getTypeChecker();
|
||||
|
||||
// Decide whether to show signature help
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user