Merge pull request #3556 from Microsoft/cancellableClassification
Make classification cancellable.
This commit is contained in:
commit
e009d68d6b
|
@ -1618,7 +1618,6 @@ namespace ts {
|
||||||
export class OperationCanceledException { }
|
export class OperationCanceledException { }
|
||||||
|
|
||||||
export class CancellationTokenObject {
|
export class CancellationTokenObject {
|
||||||
|
|
||||||
public static None: CancellationTokenObject = new CancellationTokenObject(null)
|
public static None: CancellationTokenObject = new CancellationTokenObject(null)
|
||||||
|
|
||||||
constructor(private cancellationToken: CancellationToken) {
|
constructor(private cancellationToken: CancellationToken) {
|
||||||
|
@ -6064,6 +6063,26 @@ namespace ts {
|
||||||
return convertClassifications(getEncodedSemanticClassifications(fileName, span));
|
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 {
|
function getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications {
|
||||||
synchronizeHostData();
|
synchronizeHostData();
|
||||||
|
|
||||||
|
@ -6131,7 +6150,10 @@ namespace ts {
|
||||||
function processNode(node: Node) {
|
function processNode(node: Node) {
|
||||||
// Only walk into nodes that intersect the requested span.
|
// Only walk into nodes that intersect the requested span.
|
||||||
if (node && textSpanIntersectsWith(span, node.getFullStart(), node.getFullWidth())) {
|
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;
|
let identifier = <Identifier>node;
|
||||||
|
|
||||||
// Only bother calling into the typechecker if this is an identifier that
|
// Only bother calling into the typechecker if this is an identifier that
|
||||||
|
@ -6498,6 +6520,8 @@ namespace ts {
|
||||||
|
|
||||||
// Ignore nodes that don't intersect the original span to classify.
|
// Ignore nodes that don't intersect the original span to classify.
|
||||||
if (decodedTextSpanIntersectsWith(spanStart, spanLength, element.pos, element.getFullWidth())) {
|
if (decodedTextSpanIntersectsWith(spanStart, spanLength, element.pos, element.getFullWidth())) {
|
||||||
|
checkForClassificationCancellation(element.kind);
|
||||||
|
|
||||||
let children = element.getChildren(sourceFile);
|
let children = element.getChildren(sourceFile);
|
||||||
for (let i = 0, n = children.length; i < n; i++) {
|
for (let i = 0, n = children.length; i < n; i++) {
|
||||||
let child = children[i];
|
let child = children[i];
|
||||||
|
|
|
@ -327,7 +327,8 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCancellationToken(): CancellationToken {
|
public getCancellationToken(): CancellationToken {
|
||||||
return this.shimHost.getCancellationToken();
|
var hostCancellationToken = this.shimHost.getCancellationToken();
|
||||||
|
return new ThrottledCancellationToken(hostCancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCurrentDirectory(): string {
|
public getCurrentDirectory(): string {
|
||||||
|
@ -346,6 +347,29 @@ namespace ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A cancellation that throttles calls to the host */
|
||||||
|
class ThrottledCancellationToken implements CancellationToken {
|
||||||
|
// 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) {
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
export class CoreServicesShimHostAdapter implements ParseConfigHost {
|
||||||
|
|
||||||
constructor(private shimHost: CoreServicesShimHost) {
|
constructor(private shimHost: CoreServicesShimHost) {
|
||||||
|
|
|
@ -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"));
|
|
@ -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);
|
|
|
@ -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("}"));
|
Loading…
Reference in a new issue