Merge branch 'master' into completionListWithLocalName

Conflicts:
	tests/cases/fourslash/renameLocationsForClassExpression01.ts
This commit is contained in:
Yui T 2015-07-07 15:17:42 -07:00
commit 872fdcf444
31 changed files with 341 additions and 178 deletions

View file

@ -892,7 +892,8 @@ namespace ts {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
checkStrictModeFunctionName(<FunctionExpression>node);
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, "__function");
let bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
@ -964,7 +965,8 @@ namespace ts {
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
}
else {
bindAnonymousDeclaration(node, SymbolFlags.Class, "__class");
let bindingName = node.name ? node.name.text : "__class";
bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName);
}
let symbol = node.symbol;

View file

@ -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);

View file

@ -805,4 +805,4 @@ namespace ts {
Debug.assert(false, message);
}
}
}
}

View file

@ -1246,6 +1246,11 @@ namespace ts {
return isIdentifier();
}
function nextTokenIsIdentifierOrKeyword() {
nextToken();
return isIdentifierOrKeyword();
}
function isHeritageClauseExtendsOrImplementsKeyword(): boolean {
if (token === SyntaxKind.ImplementsKeyword ||
token === SyntaxKind.ExtendsKeyword) {
@ -3172,7 +3177,7 @@ namespace ts {
if (sourceFile.languageVariant !== LanguageVariant.JSX) {
return parseTypeAssertion();
}
if(lookAhead(nextTokenIsIdentifier)) {
if(lookAhead(nextTokenIsIdentifierOrKeyword)) {
return parseJsxElementOrSelfClosingElement();
}
// Fall through
@ -3390,7 +3395,7 @@ namespace ts {
function parseJsxElementName(): EntityName {
scanJsxIdentifier();
let elementName: EntityName = parseIdentifier();
let elementName: EntityName = parseIdentifierName();
while (parseOptional(SyntaxKind.DotToken)) {
scanJsxIdentifier();
let node = <QualifiedName>createNode(SyntaxKind.QualifiedName, elementName.pos);

View file

@ -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[] {

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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[] = [];

View file

@ -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;
@ -1618,26 +1622,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.
@ -2404,6 +2388,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;
@ -2608,7 +2607,7 @@ namespace ts {
function getSyntacticDiagnostics(fileName: string) {
synchronizeHostData();
return program.getSyntacticDiagnostics(getValidSourceFile(fileName));
return program.getSyntacticDiagnostics(getValidSourceFile(fileName), cancellationToken);
}
/**
@ -2630,13 +2629,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);
}
@ -2799,7 +2798,8 @@ namespace ts {
function getCompilerOptionsDiagnostics() {
synchronizeHostData();
return program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
return program.getOptionsDiagnostics(cancellationToken).concat(
program.getGlobalDiagnostics(cancellationToken));
}
/**
@ -3029,21 +3029,30 @@ namespace ts {
let objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken);
let jsxContainer = tryGetContainingJsxElement(contextToken);
if (objectLikeContainer) {
// Object literal expression, look up possible property names from contextual type
// We're looking up possible property names from contextual/inferred/declared type.
isMemberCompletion = true;
isNewIdentifierLocation = true;
let typeForObject: Type;
let existingMembers: Declaration[];
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
// We are completing on contextual types, but may also include properties
// other than those within the declared type.
isNewIdentifierLocation = true;
typeForObject = typeChecker.getContextualType(<ObjectLiteralExpression>objectLikeContainer);
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
}
else {
else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) {
// We are *only* completing on properties from the type being destructured.
isNewIdentifierLocation = false;
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
existingMembers = (<BindingPattern>objectLikeContainer).elements;
}
else {
Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind);
}
if (!typeForObject) {
return false;
@ -5842,7 +5851,7 @@ namespace ts {
});
}
let emitOutput = program.emit(sourceFile, writeFile);
let emitOutput = program.emit(sourceFile, writeFile, cancellationToken);
return {
outputFiles,
@ -6090,6 +6099,26 @@ namespace ts {
return convertClassifications(getEncodedSemanticClassifications(fileName, span));
}
function checkForClassificationCancellation(kind: SyntaxKind) {
// We don't want to actually call back into our host on every node to find out if we've
// been canceled. That would be an enormous amount of chattyness, along with the all
// the overhead of marshalling the data to/from the host. So instead we pick a few
// reasonable node kinds to bother checking on. These node kinds represent high level
// constructs that we would expect to see commonly, but just at a far less frequent
// interval.
//
// For example, in checker.ts (around 750k) we only have around 600 of these constructs.
// That means we're calling back into the host around every 1.2k of the file we process.
// Lib.d.ts has similar numbers.
switch (kind) {
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.FunctionDeclaration:
cancellationToken.throwIfCancellationRequested();
}
}
function getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications {
synchronizeHostData();
@ -6157,7 +6186,10 @@ namespace ts {
function processNode(node: Node) {
// Only walk into nodes that intersect the requested span.
if (node && textSpanIntersectsWith(span, node.getFullStart(), node.getFullWidth())) {
if (node.kind === SyntaxKind.Identifier && !nodeIsMissing(node)) {
let kind = node.kind;
checkForClassificationCancellation(kind);
if (kind === SyntaxKind.Identifier && !nodeIsMissing(node)) {
let identifier = <Identifier>node;
// Only bother calling into the typechecker if this is an identifier that
@ -6524,6 +6556,8 @@ namespace ts {
// Ignore nodes that don't intersect the original span to classify.
if (decodedTextSpanIntersectsWith(spanStart, spanLength, element.pos, element.getFullWidth())) {
checkForClassificationCancellation(element.kind);
let children = element.getChildren(sourceFile);
for (let i = 0, n = children.length; i < n; i++) {
let child = children[i];

View file

@ -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,8 +326,9 @@ namespace ts {
}
}
public getCancellationToken(): CancellationToken {
return this.shimHost.getCancellationToken();
public getCancellationToken(): HostCancellationToken {
var hostCancellationToken = this.shimHost.getCancellationToken();
return new ThrottledCancellationToken(hostCancellationToken);
}
public getCurrentDirectory(): string {
@ -346,6 +347,29 @@ namespace ts {
}
}
/** A cancellation that throttles calls to the host */
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: HostCancellationToken) {
}
public isCancellationRequested(): boolean {
var time = Date.now();
var duration = Math.abs(time - this.lastCancellationCheckTime);
if (duration > 10) {
// Check no more than once every 10 ms.
this.lastCancellationCheckTime = time;
return this.hostCancellationToken.isCancellationRequested();
}
return false;
}
}
export class CoreServicesShimHostAdapter implements ParseConfigHost {
constructor(private shimHost: CoreServicesShimHost) {

View file

@ -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

View file

@ -28,13 +28,13 @@ function M() {
}
var v = new m<number>();
>v : <number>
>new m<number>() : <number>
>v : C<number>
>new m<number>() : C<number>
>m : typeof C
return v.f<string>();
>v.f<string>() : { t: string; x: number; }
>v.f : <T>() => { t: T; x: number; }
>v : <number>
>v : C<number>
>f : <T>() => { t: T; x: number; }
}

View file

@ -1,17 +1,19 @@
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(22,8): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(23,8): error TS2339: Property 'y' does not exist on type 'Attribs1'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(23,8): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(24,8): error TS2339: Property 'y' does not exist on type 'Attribs1'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(25,8): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(25,8): error TS2339: Property 'y' does not exist on type 'Attribs1'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(26,8): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(27,8): error TS2339: Property 'var' does not exist on type 'Attribs1'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(29,1): error TS2324: Property 'reqd' is missing in type '{ reqd: string; }'.
tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(30,8): error TS2322: Type 'number' is not assignable to type 'string'.
==== tests/cases/conformance/jsx/tsxAttributeResolution1.tsx (6 errors) ====
==== tests/cases/conformance/jsx/tsxAttributeResolution1.tsx (7 errors) ====
declare module JSX {
interface Element { }
interface IntrinsicElements {
test1: Attribs1;
test2: { reqd: string };
var: { var: string };
}
}
interface Attribs1 {
@ -40,8 +42,9 @@ tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(30,8): error TS2322: Typ
<test1 x="32" />; // Error, "32" is not number
~~~~~~
!!! error TS2322: Type 'string' is not assignable to type 'number'.
// TODO attribute 'var' should be parseable
// <test1 var="10" />; // Error, no 'var' property
<test1 var="10" />; // Error, no 'var' property
~~~
!!! error TS2339: Property 'var' does not exist on type 'Attribs1'.
<test2 />; // Error, missing reqd
~~~~~~~~~
@ -50,4 +53,6 @@ tests/cases/conformance/jsx/tsxAttributeResolution1.tsx(30,8): error TS2322: Typ
~~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
// Should be OK
<var var='var' />;

View file

@ -4,6 +4,7 @@ declare module JSX {
interface IntrinsicElements {
test1: Attribs1;
test2: { reqd: string };
var: { var: string };
}
}
interface Attribs1 {
@ -24,12 +25,13 @@ interface Attribs1 {
<test1 y={0} />; // Error, no property "y"
<test1 y="foo" />; // Error, no property "y"
<test1 x="32" />; // Error, "32" is not number
// TODO attribute 'var' should be parseable
// <test1 var="10" />; // Error, no 'var' property
<test1 var="10" />; // Error, no 'var' property
<test2 />; // Error, missing reqd
<test2 reqd={10} />; // Error, reqd is not string
// Should be OK
<var var='var' />;
//// [tsxAttributeResolution1.jsx]
@ -44,7 +46,8 @@ interface Attribs1 {
<test1 y={0}/>; // Error, no property "y"
<test1 y="foo"/>; // Error, no property "y"
<test1 x="32"/>; // Error, "32" is not number
// TODO attribute 'var' should be parseable
// <test1 var="10" />; // Error, no 'var' property
<test1 var="10"/>; // Error, no 'var' property
<test2 />; // Error, missing reqd
<test2 reqd={10}/>; // Error, reqd is not string
// Should be OK
<var var='var'/>;

View file

@ -5,6 +5,7 @@ declare module JSX {
interface IntrinsicElements {
test1: Attribs1;
test2: { reqd: string };
var: { var: string };
}
}
interface Attribs1 {
@ -25,9 +26,10 @@ interface Attribs1 {
<test1 y={0} />; // Error, no property "y"
<test1 y="foo" />; // Error, no property "y"
<test1 x="32" />; // Error, "32" is not number
// TODO attribute 'var' should be parseable
// <test1 var="10" />; // Error, no 'var' property
<test1 var="10" />; // Error, no 'var' property
<test2 />; // Error, missing reqd
<test2 reqd={10} />; // Error, reqd is not string
// Should be OK
<var var='var' />;

View file

@ -10,4 +10,5 @@
goTo.marker();
verify.completionListContains("property1");
verify.completionListContains("property2");
verify.completionListContains("property2");
verify.not.completionListAllowsNewIdentifier();

View file

@ -10,4 +10,5 @@
goTo.marker();
verify.completionListContains("property2");
verify.not.completionListContains("property1");
verify.not.completionListContains("property1");
verify.not.completionListAllowsNewIdentifier();

View file

@ -10,4 +10,5 @@
goTo.marker();
verify.completionListContains("property1");
verify.completionListContains("property2");
verify.completionListContains("property2");
verify.not.completionListAllowsNewIdentifier();

View file

@ -9,4 +9,5 @@
////var { property1/**/ } = foo;
goTo.marker();
verify.completionListContains("property1");
verify.completionListContains("property1");
verify.not.completionListAllowsNewIdentifier();

View file

@ -15,4 +15,5 @@
goTo.marker();
verify.completionListContains("propertyOfI_1");
verify.completionListContains("propertyOfI_2");
verify.not.completionListContains("property2");
verify.not.completionListContains("property2");
verify.not.completionListAllowsNewIdentifier();

View file

@ -15,4 +15,5 @@
goTo.marker();
verify.completionListContains("propertyOfI_2");
verify.not.completionListContains("propertyOfI_1");
verify.not.completionListContains("property2");
verify.not.completionListContains("property2");
verify.not.completionListAllowsNewIdentifier();

View file

@ -16,4 +16,5 @@ goTo.marker();
verify.completionListContains("property2");
verify.not.completionListContains("property1");
verify.not.completionListContains("propertyOfI_2");
verify.not.completionListContains("propertyOfI_1");
verify.not.completionListContains("propertyOfI_1");
verify.not.completionListAllowsNewIdentifier();

View file

@ -17,7 +17,9 @@ verify.completionListContains("property2");
verify.not.completionListContains("property1");
verify.not.completionListContains("propertyOfI_2");
verify.not.completionListContains("propertyOfI_1");
verify.not.completionListAllowsNewIdentifier();
goTo.marker("2");
verify.completionListContains("property1");
verify.completionListContains("property2");
verify.completionListContains("property2");
verify.not.completionListAllowsNewIdentifier();

View file

@ -10,4 +10,5 @@
goTo.marker("");
verify.completionListContains("property2");
verify.not.completionListContains("property1");
verify.not.completionListContains("prop1");
verify.not.completionListContains("prop1");
verify.not.completionListAllowsNewIdentifier();

View file

@ -10,4 +10,5 @@
goTo.marker("");
verify.completionListContains("property2");
verify.not.completionListContains("property1");
verify.not.completionListContains("property1");
verify.not.completionListAllowsNewIdentifier();

View file

@ -16,4 +16,5 @@
goTo.marker();
verify.completionListContains("x");
verify.completionListContains("y");
verify.not.completionListContains("z");
verify.not.completionListContains("z");
verify.not.completionListAllowsNewIdentifier();

View file

@ -3,7 +3,6 @@
////class Foo {
////}
////
//////The class expression Foo
////var x = class [|Foo|] {
//// doIt() {
//// return [|Foo|];

View file

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
////module M {
////}
////module N {
////}
var c = classification;
cancellation.setCancelled(1);
verifyOperationIsCancelled(() => verify.semanticClassificationsAre());
cancellation.resetCancelled();
verify.semanticClassificationsAre(
c.moduleName("M"),
c.moduleName("N"));

View file

@ -1,38 +0,0 @@
/// <reference path="fourslash.ts" />
//@Filename: findAllRefsOnDefinition-import.ts
////export class Test{
////
//// constructor(){
////
//// }
////
//// public /*1*/start(){
//// return this;
//// }
////
//// public stop(){
//// return this;
//// }
////}
//@Filename: findAllRefsOnDefinition.ts
////import Second = require("findAllRefsOnDefinition-import");
////
////var second = new Second.Test()
////second.start();
////second.stop();
goTo.file("findAllRefsOnDefinition-import.ts");
goTo.marker("1");
verify.referencesCountIs(2);
cancellation.setCancelled();
goTo.marker("1");
verifyOperationIsCancelled(() => verify.referencesCountIs(0) );
// verify that internal state is still correct
cancellation.resetCancelled();
goTo.marker("1");
verify.referencesCountIs(2);

View file

@ -0,0 +1,21 @@
/// <reference path="fourslash.ts" />
////module M {
////}
////module N {
////}
var c = classification;
cancellation.setCancelled(1);
verifyOperationIsCancelled(() => verify.syntacticClassificationsAre());
cancellation.resetCancelled();
verify.syntacticClassificationsAre(
c.keyword("module"),
c.moduleName("M"),
c.punctuation("{"),
c.punctuation("}"),
c.keyword("module"),
c.moduleName("N"),
c.punctuation("{"),
c.punctuation("}"));