From fa4b68fa6c70a318263ea4fa124b2f5b1ccc35c6 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:39:52 -0800 Subject: [PATCH 01/53] Initial test harness for incremental parser tests. --- Jakefile | 1 + src/compiler/parser.ts | 1 + src/harness/harness.ts | 79 ++++++++++ src/harness/test262Runner.ts | 77 +--------- src/services/services.ts | 8 +- tests/cases/unittests/incrementalParser.ts | 166 +++++++++++++++++++++ 6 files changed, 252 insertions(+), 80 deletions(-) create mode 100644 tests/cases/unittests/incrementalParser.ts diff --git a/Jakefile b/Jakefile index 16330305b6a..039c085ba12 100644 --- a/Jakefile +++ b/Jakefile @@ -84,6 +84,7 @@ var harnessSources = [ ].map(function (f) { return path.join(harnessDirectory, f); }).concat([ + "incrementalParser.ts", "services/colorization.ts", "services/documentRegistry.ts", "services/preProcessFile.ts" diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4f4b7bd96e0..a05b88cda87 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -359,6 +359,7 @@ module ts { case SyntaxKind.Block: case SyntaxKind.TryBlock: case SyntaxKind.FinallyBlock: + return children((node).statements); case SyntaxKind.ModuleBlock: return children((node).statements); case SyntaxKind.SourceFile: diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 4afbc98c48a..f51e492d6b5 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -111,6 +111,85 @@ module Utils { } }); } + + export function checkInvariants(node: ts.Node, parent: ts.Node): void { + if(node) { + if (node.pos < 0) { + throw new Error("node.pos < 0"); + } + if (node.end < 0) { + throw new Error("node.end < 0"); + } + if (node.end < node.pos) { + throw new Error("node.end < node.pos"); + } + if (node.parent !== parent) { + throw new Error("node.parent !== parent"); + } + if (parent) { + // Make sure each child is contained within the parent. + if (node.pos < parent.pos) { + throw new Error("node.pos < parent.pos"); + } + if (node.end > parent.end) { + throw new Error("node.end > parent.end"); + } + } + + ts.forEachChild(node, child => { + checkInvariants(child, node); + }); + + // Make sure each of the children is in order. + var currentPos = 0; + ts.forEachChild(node, + child => { + if (child.pos < currentPos) { + throw new Error("child.pos < currentPos"); + } + currentPos = child.end; + }, + (array: ts.NodeArray) => { + if (array.pos < node.pos) { + throw new Error("array.pos < node.pos"); + } + if (array.end > node.end) { + throw new Error("array.end > node.end"); + } + + if (array.pos < currentPos) { + throw new Error("array.pos < currentPos"); + } + for (var i = 0, n = array.length; i < n; i++) { + if (array[i].pos < currentPos) { + throw new Error("array[i].pos < currentPos"); + } + currentPos = array[i].end + } + + currentPos = array.end; + }); + + var childNodesAndArrays: any[] = []; + ts.forEachChild(node, child => { childNodesAndArrays.push(child) }, array => { childNodesAndArrays.push(array) }); + + for (var childName in node) { + if (childName === "parent" || childName === "nextContainer" || childName === "modifiers" || childName === "externalModuleIndicator") { + continue; + } + var child = (node)[childName]; + if (isNodeOrArray(child)) { + if (childNodesAndArrays.indexOf(child) < 0) { + throw new Error("Child when forEach'ing over node. " + (ts).SyntaxKind[node.kind] + "-" + childName); + } + } + } + } + } + + function isNodeOrArray(a: any): boolean { + return a !== undefined && typeof a.pos === "number"; + } } module Harness.Path { diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index a29c6ac8619..f9c083a2542 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -21,81 +21,6 @@ class Test262BaselineRunner extends RunnerBase { return Test262BaselineRunner.basePath + "/" + filename; } - private static checkInvariants(node: ts.Node, parent: ts.Node): void { - if (node) { - if (node.pos < 0) { - throw new Error("node.pos < 0"); - } - if (node.end < 0) { - throw new Error("node.end < 0"); - } - if (node.end < node.pos) { - throw new Error("node.end < node.pos"); - } - if (node.parent !== parent) { - throw new Error("node.parent !== parent"); - } - if (parent) { - // Make sure each child is contained within the parent. - if (node.pos < parent.pos) { - throw new Error("node.pos < parent.pos"); - } - if (node.end > parent.end) { - throw new Error("node.end > parent.end"); - } - } - - ts.forEachChild(node, child => { - Test262BaselineRunner.checkInvariants(child, node); - }); - - // Make sure each of the children is in order. - var currentPos = 0; - ts.forEachChild(node, - child => { - if (child.pos < currentPos) { - throw new Error("child.pos < currentPos"); - } - currentPos = child.end; - }, - (array: ts.NodeArray) => { - if (array.pos < node.pos) { - throw new Error("array.pos < node.pos"); - } - if (array.end > node.end) { - throw new Error("array.end > node.end"); - } - - if (array.pos < currentPos) { - throw new Error("array.pos < currentPos"); - } - for (var i = 0, n = array.length; i < n; i++) { - if (array[i].pos < currentPos) { - throw new Error("array[i].pos < currentPos"); - } - currentPos = array[i].end - } - - currentPos = array.end; - }); - - var childNodesAndArrays: any[] = []; - ts.forEachChild(node, child => { childNodesAndArrays.push(child) }, array => { childNodesAndArrays.push(array) }); - - for (var childName in node) { - if (childName === "parent" || childName === "nextContainer" || childName === "modifiers" || childName === "externalModuleIndicator") { - continue; - } - var child = (node)[childName]; - if (Test262BaselineRunner.isNodeOrArray(child)) { - if (childNodesAndArrays.indexOf(child) < 0) { - throw new Error("Child when forEach'ing over node. " + (ts).SyntaxKind[node.kind] + "-" + childName); - } - } - } - } - } - private static serializeSourceFile(file: ts.SourceFile): string { function getKindName(k: number): string { return (ts).SyntaxKind[k] @@ -264,7 +189,7 @@ class Test262BaselineRunner extends RunnerBase { it('satisfies invariants', () => { var sourceFile = testState.checker.getProgram().getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); - Test262BaselineRunner.checkInvariants(sourceFile, /*parent:*/ undefined); + Utils.checkInvariants(sourceFile, /*parent:*/ undefined); }); it('has the expected AST',() => { diff --git a/src/services/services.ts b/src/services/services.ts index b435c554420..07eafbcbeaf 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1679,7 +1679,7 @@ module ts { var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); var start = new Date().getTime(); - sourceFile = createSourceFileFromScriptSnapshot(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true); + sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true); this.host.log("SyntaxTreeCache.Initialize: createSourceFile: " + (new Date().getTime() - start)); var start = new Date().getTime(); @@ -1692,7 +1692,7 @@ module ts { var start = new Date().getTime(); sourceFile = !editRange - ? createSourceFileFromScriptSnapshot(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true) + ? createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true) : this.currentSourceFile.update(scriptSnapshot, version, /*isOpen*/ true, editRange); this.host.log("SyntaxTreeCache.Initialize: updateSourceFile: " + (new Date().getTime() - start)); @@ -1718,7 +1718,7 @@ module ts { } } - function createSourceFileFromScriptSnapshot(filename: string, scriptSnapshot: IScriptSnapshot, settings: CompilerOptions, version: string, isOpen: boolean) { + export function createLanguageServiceSourceFile(filename: string, scriptSnapshot: IScriptSnapshot, settings: CompilerOptions, version: string, isOpen: boolean): SourceFile { return SourceFileObject.createSourceFileObject(filename, scriptSnapshot, settings.target, version, isOpen); } @@ -1769,7 +1769,7 @@ module ts { var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true); var entry = lookUp(bucket, filename); if (!entry) { - var sourceFile = createSourceFileFromScriptSnapshot(filename, scriptSnapshot, compilationSettings, version, isOpen); + var sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, compilationSettings, version, isOpen); bucket[filename] = entry = { sourceFile: sourceFile, diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts new file mode 100644 index 00000000000..538996bc667 --- /dev/null +++ b/tests/cases/unittests/incrementalParser.ts @@ -0,0 +1,166 @@ +/// +/// + +module ts { + function withChange(text: IScriptSnapshot, start: number, length: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { + var contents = text.getText(0, text.getLength()); + var newContents = contents.substr(0, start) + newText + contents.substring(start + length); + + return { text: ScriptSnapshot.fromString(newContents), textChangeRange: new TextChangeRange(new TextSpan(start, length), newText.length) } + } + + function withInsert(text: IScriptSnapshot, start: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { + return withChange(text, start, 0, newText); + } + + function withDelete(text: IScriptSnapshot, start: number, length: number): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { + return withChange(text, start, length, ""); + } + + // NOTE: 'reusedElements' is the expected count of elements reused from the old tree to the new + // tree. It may change as we tweak the parser. If the count increases then that should always + // be a good thing. If it decreases, that's not great (less reusability), but that may be + // unavoidable. If it does decrease an investigation should be done to make sure that things + // are still ok and we're still appropriately reusing most of the tree. + function compareTrees(oldText: IScriptSnapshot, newText: IScriptSnapshot, textChangeRange: TextChangeRange, expectedReusedElements: number = -1): void { + // Create a tree for the new text, in a non-incremental fashion. + var options: CompilerOptions = {}; + options.target = ScriptTarget.ES5; + + var newTree = createLanguageServiceSourceFile(/*fileName:*/ "", newText, options, /*version:*/ "0", /*isOpen:*/ true); + Utils.checkInvariants(newTree, /*parent:*/ undefined); + + // Create a tree for the new text, in an incremental fashion. + var oldTree = createLanguageServiceSourceFile(/*fileName:*/ "", oldText, options, /*version:*/ "0", /*isOpen:*/ true); + Utils.checkInvariants(oldTree, /*parent:*/ undefined); + + var incrementalNewTree = oldTree.update(newText, "1", /*isOpen:*/ true, textChangeRange); + Utils.checkInvariants(incrementalNewTree, /*parent:*/ undefined); + + // We should get the same tree when doign a full or incremental parse. + assertStructuralEquals(newTree, incrementalNewTree); + + // There should be no reused nodes between two trees that are fully parsed. + Debug.assert(reusedElements(oldTree, newTree) === 0); + + if (expectedReusedElements !== -1) { + var actualReusedCount = reusedElements(oldTree, incrementalNewTree); + Debug.assert(actualReusedCount === expectedReusedElements, actualReusedCount + " !== " + expectedReusedElements); + } + } + + function assertStructuralEquals(node1: Node, node2: Node) { + if (node1 === node2) { + return; + } + + if (!node1 || !node2) { + throw new Error("!node1 || !node2"); + } + + if (node1.pos !== node2.pos) { + throw new Error("node1.pos !== node2.pos"); + } + + if (node1.end !== node2.end) { + throw new Error("node1.end !== node2.end"); + } + + if (node1.kind !== node2.kind) { + throw new Error("node1.kind !== node2.kind"); + } + + if (node1.flags !== node2.flags) { + throw new Error("node1.flags !== node2.flags"); + } + + if (node1.parserContextFlags !== node2.parserContextFlags) { + throw new Error("node1.parserContextFlags !== node2.parserContextFlags"); + } + + forEachChild(node1, + child1 => { + var childName = findChildName(node1, child1); + var child2: Node = (node2)[childName]; + + assertStructuralEquals(child1, child2); + }, + (array1: NodeArray) => { + var childName = findChildName(node1, array1); + var array2: NodeArray = (node2)[childName]; + + assertArrayStructuralEquals(array1, array2); + }); + } + + function assertArrayStructuralEquals(array1: NodeArray, array2: NodeArray) { + if (array1 === array2) { + return; + } + + if (!array1 || !array2) { + throw new Error("!array1 || !array2"); + } + + if (array1.pos !== array2.pos) { + throw new Error("array1.pos !== array2.pos"); + } + + if (array1.end !== array2.end) { + throw new Error("array1.end !== array2.end"); + } + + if (array1.length !== array2.length) { + throw new Error("array1.length !== array2.length"); + } + + for (var i = 0, n = array1.length; i < n; i++) { + assertStructuralEquals(array1[i], array2[i]); + } + } + + function findChildName(parent: any, child: any) { + for (var name in parent) { + if (parent.hasOwnProperty(name) && parent[name] === child) { + return name; + } + } + + throw new Error("Could not find child in parent"); + } + + function reusedElements(oldNode: SourceFile, newNode: SourceFile): number { + var allOldElements = collectElements(oldNode); + var allNewElements = collectElements(newNode); + + return filter(allOldElements, v => contains(allNewElements, v)).length; + } + + function collectElements(node: Node) { + var result: Node[] = []; + visit(node); + return result; + + function visit(node: Node) { + result.push(node); + forEachChild(node, visit); + } + } + + describe('Incremental',() => { + it('Inserting into method',() => { + var source = "class C {\r\n" + + " public foo1() { }\r\n" + + " public foo2() {\r\n" + + " return 1;\r\n" + + " }\r\n" + + " public foo3() { }\r\n" + + "}"; + + var oldText = ScriptSnapshot.fromString(source); + var semicolonIndex = source.indexOf(";"); + var newTextAndChange = withInsert(oldText, semicolonIndex, " + 1"); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + }); +} \ No newline at end of file From 783b0e53d1fa815a22e7ebe81fe985fc0caa6832 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:43:45 -0800 Subject: [PATCH 02/53] Remove unnecessary switch case. --- src/compiler/parser.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a05b88cda87..4f4b7bd96e0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -359,7 +359,6 @@ module ts { case SyntaxKind.Block: case SyntaxKind.TryBlock: case SyntaxKind.FinallyBlock: - return children((node).statements); case SyntaxKind.ModuleBlock: return children((node).statements); case SyntaxKind.SourceFile: From 9d457701cc707533fe8eafe038c18a582134797d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:47:19 -0800 Subject: [PATCH 03/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 538996bc667..260a6855b5e 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -162,5 +162,20 @@ module ts { var newTextAndChange = withInsert(oldText, semicolonIndex, " + 1"); compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Deleting from method',() => { + var source = "class C {\r\n" + + " public foo1() { }\r\n" + + " public foo2() {\r\n" + + " return 1 + 1;\r\n" + + " }\r\n" + + " public foo3() { }\r\n" + + "}"; + + var index = source.indexOf("+ 1"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, index, "+ 1".length); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From a268cbf2d8c065893405445ec532d9e2fa100a70 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:50:31 -0800 Subject: [PATCH 04/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 260a6855b5e..9a80c400899 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -177,5 +177,15 @@ module ts { var newTextAndChange = withDelete(oldText, index, "+ 1".length); compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Regular expression 1', () => { + var source = "class C { public foo1() { /; } public foo2() { return 1;} public foo3() { } }"; + + var semicolonIndex = source.indexOf(";}"); + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, semicolonIndex, "/"); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From 2497d9abdf38e863a7e9013439dfca4324fb9670 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:51:55 -0800 Subject: [PATCH 05/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 9a80c400899..6029c4b6113 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -187,5 +187,15 @@ module ts { var newTextAndChange = withInsert(oldText, semicolonIndex, "/"); compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Regular expression 2',() => { + var source = "class C { public foo1() { ; } public foo2() { return 1/;} public foo3() { } }"; + + var semicolonIndex = source.indexOf(";"); + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, semicolonIndex, "/"); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From d8ff734bfc981a99efac3895d643e5a45cfc4864 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:53:18 -0800 Subject: [PATCH 06/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 6029c4b6113..44fa9f4a693 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -160,6 +160,7 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var semicolonIndex = source.indexOf(";"); var newTextAndChange = withInsert(oldText, semicolonIndex, " + 1"); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); @@ -175,6 +176,7 @@ module ts { var index = source.indexOf("+ 1"); var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withDelete(oldText, index, "+ 1".length); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); @@ -182,9 +184,9 @@ module ts { var source = "class C { public foo1() { /; } public foo2() { return 1;} public foo3() { } }"; var semicolonIndex = source.indexOf(";}"); - var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, semicolonIndex, "/"); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); @@ -192,9 +194,19 @@ module ts { var source = "class C { public foo1() { ; } public foo2() { return 1/;} public foo3() { } }"; var semicolonIndex = source.indexOf(";"); - var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, semicolonIndex, "/"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Regular comment 1',() => { + var source = "class C { public foo1() { /; } public foo2() { return 1; } public foo3() { } }"; + + var semicolonIndex = source.indexOf(";"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, semicolonIndex, "/"); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); }); From 4de7fa0181ba3d721fed6769e49e1a71b3260309 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:54:06 -0800 Subject: [PATCH 07/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 44fa9f4a693..89c350084e6 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -200,7 +200,7 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); - it('Regular comment 1',() => { + it('Comment 1',() => { var source = "class C { public foo1() { /; } public foo2() { return 1; } public foo3() { } }"; var semicolonIndex = source.indexOf(";"); @@ -209,5 +209,14 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Comment 2',() => { + var source = "class C { public foo1() { /; } public foo2() { return 1; } public foo3() { } }"; + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, 0, "//"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From bcffd5331c05f53d2f3f5e0c5f32ff6b09c1d517 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:55:02 -0800 Subject: [PATCH 08/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 89c350084e6..e2dd9b0f939 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -218,5 +218,14 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Comment 3',() => { + var source = "//class C { public foo1() { /; } public foo2() { return 1; } public foo3() { } }"; + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, 0, 2); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From 778e180e400a5aef10c1494c114c612bf49de335 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:56:00 -0800 Subject: [PATCH 09/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index e2dd9b0f939..d2cc0d49892 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -227,5 +227,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Comment 4',() => { + var source = "class C { public foo1() { /; } public foo2() { */ return 1; } public foo3() { } }"; + + var index = source.indexOf(";"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index, "*"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From de84ddd8151da44b38abdf5875b393e07d155690 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:57:51 -0800 Subject: [PATCH 10/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index d2cc0d49892..41cee54c6c6 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -237,5 +237,20 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Parameter 1',() => { + // Should be able to reuse all the parameters. + var source = "class C {\r\n" + + " public foo2(a, b, c, d) {\r\n" + + " return 1;\r\n" + + " }\r\n" + + "}"; + + var semicolonIndex = source.indexOf(";"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, semicolonIndex, " + 1"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From 45f87131ab2a58040c601369ffdfcd63ab9c8dc4 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 16:59:02 -0800 Subject: [PATCH 11/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 41cee54c6c6..a68e794418d 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -252,5 +252,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Type member 1',() => { + // Should be able to reuse most of the type members. + var source = "interface I { a: number; b: string; (c): d; new (e): f; g(): h }"; + + var index = source.indexOf(": string"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index, "?"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From a0a8ee0d4f7227862ed4a5f46eeeca4c0ffee011 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:05:14 -0800 Subject: [PATCH 12/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index a68e794418d..d69343312e2 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -263,5 +263,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Enum element 1',() => { + // Should be able to reuse most of the enum elements. + var source = "enum E { a = 1, b = 1 << 1, c = 3, e = 4, f = 5, g = 7, h = 8, i = 9, j = 10 }"; + + var index = source.indexOf("<<"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, index, 2, "+"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From e41bed82e4201589850d44421be47f07469bad83 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:06:44 -0800 Subject: [PATCH 13/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index d69343312e2..e9031e45b50 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -274,5 +274,19 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Strict mode 1',() => { + // In non-strict mode 'package' means nothing and can be reused. In strict mode though + // we'll have to reparse the nodes (and generate an error for 'package();' + // + // Note: in this test we don't actually add 'use strict'. This is so we can compare + // reuse with/without a strict mode change. + var source = "foo1();\r\nfoo1();\r\nfoo1();\r\package();"; + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, 0, "'strict';\r\n"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From bb34a20b4d6feb6544e860915c7d5c3050c3152d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:07:51 -0800 Subject: [PATCH 14/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index e9031e45b50..df4c6fdc694 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -288,5 +288,17 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Strict mode 2',() => { + // In non-strict mode 'package' means nothing and can be reused. In strict mode though + // we'll have to reparse the nodes (and generate an error for 'package();' + var source = "foo1();\r\nfoo1();\r\nfoo1();\r\package();"; + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, 0, "'use strict';\r\n"); + + // Note the decreased reuse of nodes compared to 'Strict mode 1' + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From e59ba41d17097419b4b60902b6d00aba86633d25 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:09:33 -0800 Subject: [PATCH 15/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index df4c6fdc694..ad4d2c01c7a 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -300,5 +300,20 @@ module ts { // Note the decreased reuse of nodes compared to 'Strict mode 1' compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Strict mode 3',() => { + // In non-strict mode 'package' means nothing and can be reused. In strict mode though + // we'll have to reparse the nodes (and generate an error for 'package();' + // + // Note: in this test we don't actually remove 'use strict'. This is so we can compare + // reuse with/without a strict mode change. + var source = "'strict';\r\nfoo1();\r\nfoo1();\r\nfoo1();\r\npackage();"; + + var index = source.indexOf('f'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, 0, index); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From 22f39c5f9940461427f495afcfb99ebaa90df616 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:11:32 -0800 Subject: [PATCH 16/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index ad4d2c01c7a..4ed24357d5c 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -315,5 +315,18 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Strict mode 4',() => { + // In non-strict mode 'package' means nothing and can be reused. In strict mode though + // we'll have to reparse the nodes (and generate an error for 'package();' + var source = "'use strict';\r\nfoo1();\r\nfoo1();\r\nfoo1();\r\npackage();"; + + var index = source.indexOf('f'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, 0, index); + + // Note the decreased reuse of nodes compared to testStrictMode3 + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From 7f605332fc455a2e5acf5190eba7c7197fab3932 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:12:44 -0800 Subject: [PATCH 17/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 4ed24357d5c..1e74c0fc843 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -328,5 +328,15 @@ module ts { // Note the decreased reuse of nodes compared to testStrictMode3 compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Strict mode 5',() => { + var source = "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + + var index = source.indexOf('b'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, index, 6, "strict"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); }); } \ No newline at end of file From fa86c88c47b9106021498f804ee5875f63a4c526 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:13:33 -0800 Subject: [PATCH 18/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 1e74c0fc843..b3732f9333b 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -338,5 +338,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Strict mode 6',() => { + var source = "'use strict';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + + var index = source.indexOf('s'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, index, 6, "blahhh"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 37); + }); }); } \ No newline at end of file From d5496779117506832cd1e8e5a716fd9f72821fb1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:15:13 -0800 Subject: [PATCH 19/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index b3732f9333b..8f41ce5ea7c 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -346,7 +346,17 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withChange(oldText, index, 6, "blahhh"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 37); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Strict mode 7',() => { + var source = "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + + var index = source.indexOf('f'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, 0, index); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); }); } \ No newline at end of file From 82098d1568ec92f56dd37d8887e5405cff0422dd Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:18:18 -0800 Subject: [PATCH 20/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 8f41ce5ea7c..f2be1fdaf69 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -358,5 +358,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + + it('Parenthesized expression to arrow function',() => { + var source = "var v = (a, b, c, d, e)"; + + var index = source.indexOf('a'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index + 1, ":"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); }); } \ No newline at end of file From a1b8a7891b61ec73e87db8f2be1d7cf6675900be Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:19:44 -0800 Subject: [PATCH 21/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index f2be1fdaf69..23fa6b6f1b3 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -368,5 +368,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); }); + + it('Arrow function to parenthesized expression',() => { + var source = "var v = (a:, b, c, d, e)"; + + var index = source.indexOf(':'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, index, 1); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); }); } \ No newline at end of file From d5e2ab993e93c5aba593054b5a2ad444e928b46b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:20:44 -0800 Subject: [PATCH 22/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 23fa6b6f1b3..9749b58d1da 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -378,5 +378,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); }); + + it('Speculative generic lookahead 1',() => { + var source = "var v = Fe"; + + var index = source.indexOf('b'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index + 1, ",x"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); }); } \ No newline at end of file From 6058dbbc2f56bc7e86dbb287e8cf98303366749b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:21:30 -0800 Subject: [PATCH 23/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 9749b58d1da..ec8af54ca73 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -388,5 +388,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); }); + + it('Speculative generic lookahead 2',() => { + var source = "var v = Fe"; + + var index = source.indexOf('b'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index + 1, ",x"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); }); } \ No newline at end of file From c482a9e0e3a2845a21aa28254f4b0e6437fe34b1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:22:15 -0800 Subject: [PATCH 24/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index ec8af54ca73..3e51d8de8cc 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -398,5 +398,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); }); + + it('Speculative generic lookahead 3',() => { + var source = "var v = Fe"; + + var index = source.indexOf('b'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index + 1, ",x"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); }); } \ No newline at end of file From 1cd2fb4333206e1d022d23aa5f0e74e1a59f6674 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:23:14 -0800 Subject: [PATCH 25/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 3e51d8de8cc..2ff47f52825 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -408,5 +408,15 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); }); + + it('Speculative generic lookahead 4',() => { + var source = "var v = Fe"; + + var index = source.indexOf('b'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index + 1, ",x"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); }); } \ No newline at end of file From c7fcbb9f6b69b6152bcc00a32aa7f7bbeda4fb30 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:29:52 -0800 Subject: [PATCH 26/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 2ff47f52825..5ed3103e346 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -147,6 +147,18 @@ module ts { } } + function deleteCode(source: string, index: number, toDelete: string) { + var repeat = toDelete.length; + + for (var i = 0; i < repeat; i++) { + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, index, 1); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + + source = newTextAndChange.text.getText(0, newTextAndChange.text.getLength()); + } + } + describe('Incremental',() => { it('Inserting into method',() => { var source = "class C {\r\n" + @@ -418,5 +430,14 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); }); + + // Simulated typing tests. + + it('Type extends clause 1',() => { + var source = "interface IFoo { }\r\ninterface Array extends IFoo { }"; + + var index = source.indexOf('extends'); + deleteCode(source, index, "extends IFoo"); + }); }); } \ No newline at end of file From c436ff47a1718f0137fb37aa70426246350fa0fd Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:33:15 -0800 Subject: [PATCH 27/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 5ed3103e346..9f4dba5f9f7 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -431,6 +431,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); }); + it('Assertion to arrow function',() => { + var source = "var v = (a);"; + + var index = source.indexOf(';'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index, " => 1"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From c307d306c03a39de7643095f34b4e7d68e4cd72c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:34:26 -0800 Subject: [PATCH 28/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 9f4dba5f9f7..7c81320678f 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -441,6 +441,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Arrow function to assertion',() => { + var source = "var v = (a) => 1;"; + + var index = source.indexOf(' =>'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, index, " => 1".length); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From e564fa5c9d7776908a86d8342f624af6f0a58a0a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:37:17 -0800 Subject: [PATCH 29/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 7c81320678f..185f1510e2c 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -451,6 +451,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Contextual shift to shift-equals',() => { + var source = "var v = 1 >> = 2"; + + var index = source.indexOf('>> ='); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, index + 2, 1); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 666363a7de4f9f6222049069bbd8c9a03d5ab916 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:42:36 -0800 Subject: [PATCH 30/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 185f1510e2c..a464bdbe49d 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -461,6 +461,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Contextual shift-equals to shift',() => { + var source = "var v = 1 >>= 2"; + + var index = source.indexOf('>>='); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index + 2, " "); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 5b2778c200a90a4bddff8d32bdcf8429cd2cc4ab Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:45:50 -0800 Subject: [PATCH 31/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index a464bdbe49d..38b1716e21a 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -471,6 +471,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Contextual shift to generic invocation',() => { + var source = "var v = T>>(2)"; + + var index = source.indexOf('T'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index, "Foo { From 418c0d9d91ff169a20331744b0ec367b65b2138a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:57:13 -0800 Subject: [PATCH 32/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 38b1716e21a..531388b5cab 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -481,6 +481,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Test generic invocation to contextual shift',() => { + var source = "var v = Foo>(2)"; + + var index = source.indexOf('Foo { From b8942992a02e47899244b8ff105423aff78229d6 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 17:58:23 -0800 Subject: [PATCH 33/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 531388b5cab..50387a32def 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -491,6 +491,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Contextual shift to generic type and initializer',() => { + var source = "var v = T>>=2;"; + + var index = source.indexOf('='); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, index, "= ".length, ": Foo { From 18f9acb7fc88ef12cfae3d95479a2f317a541c1f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:00:08 -0800 Subject: [PATCH 34/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 50387a32def..fc2a4fd452a 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -501,6 +501,17 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Generic type and initializer to contextual shift',() => { + var source = "var v : Foo>=2;"; + + var index = source.indexOf(':'); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, index, ": Foo { + var source = "var v = (a, b) = c"; + + var index = source.indexOf("= c") + 1; + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index, ">"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); it('Arrow function to parenthesized expression',() => { From ec13fbee96c2d0f03d906991c68cb67544fd863c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:05:45 -0800 Subject: [PATCH 36/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 52d40c1de76..9027d58a312 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -391,14 +391,24 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); - it('Arrow function to parenthesized expression',() => { + it('Arrow function to parenthesized expression 1',() => { var source = "var v = (a:, b, c, d, e)"; var index = source.indexOf(':'); var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withDelete(oldText, index, 1); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Arrow function to parenthesized expression 2',() => { + var source = "var v = (a, b) => c"; + + var index = source.indexOf(">"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, index, 1); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); it('Speculative generic lookahead 1',() => { From d6fa98d00b752bc64b2118dbd40cab3d8ab196d6 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:07:48 -0800 Subject: [PATCH 37/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 9027d58a312..6332b3f53f1 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -532,6 +532,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Arithmetic operator to type argument list',() => { + var source = "var v = new Dictionary0"; + + var index = source.indexOf("0"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, index, 1, "()"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 78c4b92216863c75b4b039f800d39daa68b81796 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:10:15 -0800 Subject: [PATCH 38/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 6332b3f53f1..169be8474ee 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -542,6 +542,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Type argument list to arithmetic operator',() => { + var source = "var v = new Dictionary()"; + + var index = source.indexOf("()"); + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, index, 2); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 025dd23c1bcfab8812f7b1b498780132b0bf58e8 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:11:56 -0800 Subject: [PATCH 39/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 169be8474ee..98f100380f4 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -549,7 +549,18 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withDelete(oldText, index, 2); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Yield context 1',() => { + // We're changing from a non-generator to a genarator. We can't reuse statement nodes. + var source = "function foo() {\r\nyield(foo1);\r\n}"; + + var oldText = ScriptSnapshot.fromString(source); + var index = source.indexOf("foo"); + var newTextAndChange = withInsert(oldText, index, "*"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); // Simulated typing tests. From 197b62e92abb00113c482019cf7ee7c99b298b87 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:13:09 -0800 Subject: [PATCH 40/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 98f100380f4..e0800c2c51d 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -563,6 +563,17 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Yield context 2',() => { + // We're changing from a generator to a non-genarator. We can't reuse statement nodes. + var source = "function *foo() {\r\nyield(foo1);\r\n}"; + + var oldText = ScriptSnapshot.fromString(source); + var index = source.indexOf("*"); + var newTextAndChange = withDelete(oldText, index, "*".length); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From afec0fb9f08f2aab8a61321cc561c1edb4284825 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:17:11 -0800 Subject: [PATCH 41/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index e0800c2c51d..a2d296f459e 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -574,6 +574,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Delete semicolon',() => { + var source = "export class Foo {\r\n}\r\n\r\nexport var foo = new Foo();\r\n\r\n export function test(foo: Foo) {\r\n return true;\r\n }\r\n"; + + var oldText = ScriptSnapshot.fromString(source); + var index = source.lastIndexOf(";"); + var newTextAndChange = withDelete(oldText, index, 1); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 9b53947d5111c7be866dc918ff4cd83b15637e4c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:23:25 -0800 Subject: [PATCH 42/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index a2d296f459e..35f75752419 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -584,6 +584,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Edit after empty type parameter list',() => { + var source = "class Dictionary<> { }\r\nvar y;\r\n"; + + var oldText = ScriptSnapshot.fromString(source); + var index = source.length; + var newTextAndChange = withInsert(oldText, index, "var x;"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From c489c4fcfec9597770c8513896c09383e87adbd3 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:24:16 -0800 Subject: [PATCH 43/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 35f75752419..1185e91f5b9 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -594,6 +594,16 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Delete parameter after comment',() => { + var source = "function fn(/* comment! */ a: number, c) { }"; + + var oldText = ScriptSnapshot.fromString(source); + var index = source.indexOf("a:"); + var newTextAndChange = withDelete(oldText, index, "a: number,".length); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From dad3faecf3bdfddf7ab52f05beb92a30b1cdb8a0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:25:10 -0800 Subject: [PATCH 44/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 1185e91f5b9..9dbb2839c69 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -604,6 +604,20 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Modifier added to accessor',() => { + var source = + "class C {\ + set Bar(bar:string) {}\ +}\ +var o2 = { set Foo(val:number) { } };"; + + var oldText = ScriptSnapshot.fromString(source); + var index = source.indexOf("set"); + var newTextAndChange = withInsert(oldText, index, "public "); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 467d303c67aef502d61f03d16c0d79916cc66dc7 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:26:50 -0800 Subject: [PATCH 45/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 9dbb2839c69..74a9c2fae58 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -618,6 +618,22 @@ var o2 = { set Foo(val:number) { } };"; compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Insert parameter ahead of parameter',() => { + var source = + "alert(100);\ +\ +class OverloadedMonster {\ +constructor();\ +constructor(name) { }\ +}"; + + var oldText = ScriptSnapshot.fromString(source); + var index = source.indexOf("100"); + var newTextAndChange = withInsert(oldText, index, "'1', "); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From b8bb8e999871144bc0b475e05ae3fe74587605ee Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:27:59 -0800 Subject: [PATCH 46/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 74a9c2fae58..67078b788bc 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -606,7 +606,7 @@ module ts { it('Modifier added to accessor',() => { var source = - "class C {\ +"class C {\ set Bar(bar:string) {}\ }\ var o2 = { set Foo(val:number) { } };"; @@ -620,7 +620,7 @@ var o2 = { set Foo(val:number) { } };"; it('Insert parameter ahead of parameter',() => { var source = - "alert(100);\ +"alert(100);\ \ class OverloadedMonster {\ constructor();\ @@ -634,6 +634,19 @@ constructor(name) { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Insert declare modifier before module',() => { + var source = +"module mAmbient {\ +module m3 { }\ +}"; + + var oldText = ScriptSnapshot.fromString(source); + var index = 0; + var newTextAndChange = withInsert(oldText, index, "declare "); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 01ead476cf59f60578dac2f181f04ed008d920ce Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:29:18 -0800 Subject: [PATCH 47/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 67078b788bc..2571846f6f4 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -192,7 +192,7 @@ module ts { compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); - it('Regular expression 1', () => { + it('Regular expression 1',() => { var source = "class C { public foo1() { /; } public foo2() { return 1;} public foo3() { } }"; var semicolonIndex = source.indexOf(";}"); @@ -606,7 +606,7 @@ module ts { it('Modifier added to accessor',() => { var source = -"class C {\ + "class C {\ set Bar(bar:string) {}\ }\ var o2 = { set Foo(val:number) { } };"; @@ -620,7 +620,7 @@ var o2 = { set Foo(val:number) { } };"; it('Insert parameter ahead of parameter',() => { var source = -"alert(100);\ + "alert(100);\ \ class OverloadedMonster {\ constructor();\ @@ -636,7 +636,7 @@ constructor(name) { }\ it('Insert declare modifier before module',() => { var source = -"module mAmbient {\ + "module mAmbient {\ module m3 { }\ }"; @@ -647,6 +647,21 @@ module m3 { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Insert function above arrow function with comment',() => { + + var source = + "\ +() =>\ + // do something\ +0;"; + + var oldText = ScriptSnapshot.fromString(source); + var index = 0; + var newTextAndChange = withInsert(oldText, index, "function Foo() { }"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 3928f743ac39620ec79c984af36b56f13f2024e8 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:30:40 -0800 Subject: [PATCH 48/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 2571846f6f4..e71f742e697 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -648,7 +648,6 @@ module m3 { }\ }); it('Insert function above arrow function with comment',() => { - var source = "\ () =>\ @@ -659,7 +658,17 @@ module m3 { }\ var index = 0; var newTextAndChange = withInsert(oldText, index, "function Foo() { }"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Finish incomplete regular expression',() => { + var source = "while (true) /3; return;" + + var oldText = ScriptSnapshot.fromString(source); + var index = source.length - 1; + var newTextAndChange = withInsert(oldText, index, "/"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); // Simulated typing tests. From 58d36afbec94d72c678b41f2b0fc156a7a14202d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:32:43 -0800 Subject: [PATCH 49/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index e71f742e697..8f0b0c814dd 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -671,6 +671,16 @@ module m3 { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Regular expression to divide operation',() => { + var source = "return;\r\nwhile (true) /3/g;" + + var oldText = ScriptSnapshot.fromString(source); + var index = source.indexOf("while"); + var newTextAndChange = withDelete(oldText, index, "while ".length); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 3c35b9097fa8b18173f53f85da745622879df357 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:35:23 -0800 Subject: [PATCH 50/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 8f0b0c814dd..49607ed68d4 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -681,6 +681,16 @@ module m3 { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Divide operation to regular expression',() => { + var source = "return;\r\n(true) /3/g;" + + var oldText = ScriptSnapshot.fromString(source); + var index = source.indexOf("("); + var newTextAndChange = withInsert(oldText, index, "while "); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From 2a845726ab51878dfc14f0d5aa5ce8aa61e90b6f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 18:36:32 -0800 Subject: [PATCH 51/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 49607ed68d4..e1b4fa0f00f 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -691,6 +691,18 @@ module m3 { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Unterminated comment after keyword converted to identifier',() => { + // 'public' as a keyword should be incrementally unusable (because it has an + // unterminated comment). When we convert it to an identifier, that shouldn't + // change anything, and we should still get the same errors. + var source = "return; a.public /*" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, 0, ""); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + // Simulated typing tests. it('Type extends clause 1',() => { From aa30ac8a9c5991f15c92bcda8ccd96ba02d9ea6c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 19:37:26 -0800 Subject: [PATCH 52/53] Add incremental test. --- tests/cases/unittests/incrementalParser.ts | 64 ++++++++++++++++++---- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index e1b4fa0f00f..440ffc99f7d 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -17,24 +17,28 @@ module ts { return withChange(text, start, length, ""); } + function createTree(text: IScriptSnapshot, version: string) { + var options: CompilerOptions = {}; + options.target = ScriptTarget.ES5; + + return createLanguageServiceSourceFile(/*fileName:*/ "", text, options, version, /*isOpen:*/ true) + } + // NOTE: 'reusedElements' is the expected count of elements reused from the old tree to the new // tree. It may change as we tweak the parser. If the count increases then that should always // be a good thing. If it decreases, that's not great (less reusability), but that may be // unavoidable. If it does decrease an investigation should be done to make sure that things // are still ok and we're still appropriately reusing most of the tree. - function compareTrees(oldText: IScriptSnapshot, newText: IScriptSnapshot, textChangeRange: TextChangeRange, expectedReusedElements: number = -1): void { - // Create a tree for the new text, in a non-incremental fashion. - var options: CompilerOptions = {}; - options.target = ScriptTarget.ES5; + function compareTrees(oldText: IScriptSnapshot, newText: IScriptSnapshot, textChangeRange: TextChangeRange, expectedReusedElements: number, oldTree?: SourceFile): SourceFile { + oldTree = oldTree || createTree(oldText, /*version:*/ "."); + Utils.checkInvariants(oldTree, /*parent:*/ undefined); - var newTree = createLanguageServiceSourceFile(/*fileName:*/ "", newText, options, /*version:*/ "0", /*isOpen:*/ true); + // Create a tree for the new text, in a non-incremental fashion. + var newTree = createTree(newText, oldTree.version + "."); Utils.checkInvariants(newTree, /*parent:*/ undefined); // Create a tree for the new text, in an incremental fashion. - var oldTree = createLanguageServiceSourceFile(/*fileName:*/ "", oldText, options, /*version:*/ "0", /*isOpen:*/ true); - Utils.checkInvariants(oldTree, /*parent:*/ undefined); - - var incrementalNewTree = oldTree.update(newText, "1", /*isOpen:*/ true, textChangeRange); + var incrementalNewTree = oldTree.update(newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange); Utils.checkInvariants(incrementalNewTree, /*parent:*/ undefined); // We should get the same tree when doign a full or incremental parse. @@ -47,6 +51,8 @@ module ts { var actualReusedCount = reusedElements(oldTree, incrementalNewTree); Debug.assert(actualReusedCount === expectedReusedElements, actualReusedCount + " !== " + expectedReusedElements); } + + return incrementalNewTree; } function assertStructuralEquals(node1: Node, node2: Node) { @@ -149,13 +155,27 @@ module ts { function deleteCode(source: string, index: number, toDelete: string) { var repeat = toDelete.length; - + var oldTree = createTree(ScriptSnapshot.fromString(source), /*version:*/ "."); for (var i = 0; i < repeat; i++) { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withDelete(oldText, index, 1); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + var newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree); source = newTextAndChange.text.getText(0, newTextAndChange.text.getLength()); + oldTree = newTree; + } + } + + function insertCode(source: string, index: number, toInsert: string) { + var repeat = toInsert.length; + var oldTree = createTree(ScriptSnapshot.fromString(source), /*version:*/ "."); + for (var i = 0; i < repeat; i++) { + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, index + i, toInsert.charAt(i)); + var newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree); + + source = newTextAndChange.text.getText(0, newTextAndChange.text.getLength()); + oldTree = newTree; } } @@ -711,5 +731,27 @@ module m3 { }\ var index = source.indexOf('extends'); deleteCode(source, index, "extends IFoo"); }); + + it('Type after incomplete enum 1',() => { + var source = "function foo() {\r\n" + + " function getOccurrencesAtPosition() {\r\n" + + " switch (node) {\r\n" + + " enum \r\n" + + " }\r\n" + + " \r\n" + + " return undefined;\r\n" + + " \r\n" + + " function keywordToReferenceEntry() {\r\n" + + " }\r\n" + + " }\r\n" + + " \r\n" + + " return {\r\n" + + " getEmitOutput: (filename): Bar => null,\r\n" + + " };\r\n" + + " }"; + + var index = source.indexOf("enum ") + "enum ".length; + insertCode(source, index, "Fo"); + }); }); } \ No newline at end of file From dd2c869d7b216bb13d5cc6ae14f65e3002c6523f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 9 Dec 2014 19:49:40 -0800 Subject: [PATCH 53/53] Use chai asserts. --- src/harness/harness.ts | 56 ++++++-------------- src/harness/test262Runner.ts | 2 +- tests/cases/unittests/incrementalParser.ts | 60 ++++++---------------- 3 files changed, 35 insertions(+), 83 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index f51e492d6b5..b6f21d91333 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -112,58 +112,37 @@ module Utils { }); } - export function checkInvariants(node: ts.Node, parent: ts.Node): void { - if(node) { - if (node.pos < 0) { - throw new Error("node.pos < 0"); - } - if (node.end < 0) { - throw new Error("node.end < 0"); - } - if (node.end < node.pos) { - throw new Error("node.end < node.pos"); - } - if (node.parent !== parent) { - throw new Error("node.parent !== parent"); - } + export function assertInvariants(node: ts.Node, parent: ts.Node): void { + if (node) { + assert.isFalse(node.pos < 0, "node.pos < 0"); + assert.isFalse(node.end < 0, "node.end < 0"); + assert.isFalse(node.end < node.pos, "node.end < node.pos"); + assert.equal(node.parent, parent, "node.parent !== parent"); + if (parent) { // Make sure each child is contained within the parent. - if (node.pos < parent.pos) { - throw new Error("node.pos < parent.pos"); - } - if (node.end > parent.end) { - throw new Error("node.end > parent.end"); - } + assert.isFalse(node.pos < parent.pos, "node.pos < parent.pos"); + assert.isFalse(node.end > parent.end, "node.end > parent.end"); } ts.forEachChild(node, child => { - checkInvariants(child, node); + assertInvariants(child, node); }); // Make sure each of the children is in order. var currentPos = 0; ts.forEachChild(node, child => { - if (child.pos < currentPos) { - throw new Error("child.pos < currentPos"); - } + assert.isFalse(child.pos < currentPos, "child.pos < currentPos"); currentPos = child.end; }, (array: ts.NodeArray) => { - if (array.pos < node.pos) { - throw new Error("array.pos < node.pos"); - } - if (array.end > node.end) { - throw new Error("array.end > node.end"); - } + assert.isFalse(array.pos < node.pos, "array.pos < node.pos"); + assert.isFalse(array.end > node.end, "array.end > node.end"); + assert.isFalse(array.pos < currentPos, "array.pos < currentPos"); - if (array.pos < currentPos) { - throw new Error("array.pos < currentPos"); - } for (var i = 0, n = array.length; i < n; i++) { - if (array[i].pos < currentPos) { - throw new Error("array[i].pos < currentPos"); - } + assert.isFalse(array[i].pos < currentPos, "array[i].pos < currentPos"); currentPos = array[i].end } @@ -179,9 +158,8 @@ module Utils { } var child = (node)[childName]; if (isNodeOrArray(child)) { - if (childNodesAndArrays.indexOf(child) < 0) { - throw new Error("Child when forEach'ing over node. " + (ts).SyntaxKind[node.kind] + "-" + childName); - } + assert.isFalse(childNodesAndArrays.indexOf(child) < 0, + "Missing child when forEach'ing over node: " + (ts).SyntaxKind[node.kind] + "-" + childName); } } } diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index f9c083a2542..b53011237b7 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -189,7 +189,7 @@ class Test262BaselineRunner extends RunnerBase { it('satisfies invariants', () => { var sourceFile = testState.checker.getProgram().getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); - Utils.checkInvariants(sourceFile, /*parent:*/ undefined); + Utils.assertInvariants(sourceFile, /*parent:*/ undefined); }); it('has the expected AST',() => { diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 440ffc99f7d..f1e59809400 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -31,25 +31,25 @@ module ts { // are still ok and we're still appropriately reusing most of the tree. function compareTrees(oldText: IScriptSnapshot, newText: IScriptSnapshot, textChangeRange: TextChangeRange, expectedReusedElements: number, oldTree?: SourceFile): SourceFile { oldTree = oldTree || createTree(oldText, /*version:*/ "."); - Utils.checkInvariants(oldTree, /*parent:*/ undefined); + Utils.assertInvariants(oldTree, /*parent:*/ undefined); // Create a tree for the new text, in a non-incremental fashion. var newTree = createTree(newText, oldTree.version + "."); - Utils.checkInvariants(newTree, /*parent:*/ undefined); + Utils.assertInvariants(newTree, /*parent:*/ undefined); // Create a tree for the new text, in an incremental fashion. var incrementalNewTree = oldTree.update(newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange); - Utils.checkInvariants(incrementalNewTree, /*parent:*/ undefined); + Utils.assertInvariants(incrementalNewTree, /*parent:*/ undefined); // We should get the same tree when doign a full or incremental parse. assertStructuralEquals(newTree, incrementalNewTree); // There should be no reused nodes between two trees that are fully parsed. - Debug.assert(reusedElements(oldTree, newTree) === 0); + assert.isTrue(reusedElements(oldTree, newTree) === 0); if (expectedReusedElements !== -1) { var actualReusedCount = reusedElements(oldTree, incrementalNewTree); - Debug.assert(actualReusedCount === expectedReusedElements, actualReusedCount + " !== " + expectedReusedElements); + assert.equal(actualReusedCount, expectedReusedElements, actualReusedCount + " !== " + expectedReusedElements); } return incrementalNewTree; @@ -60,29 +60,13 @@ module ts { return; } - if (!node1 || !node2) { - throw new Error("!node1 || !node2"); - } - - if (node1.pos !== node2.pos) { - throw new Error("node1.pos !== node2.pos"); - } - - if (node1.end !== node2.end) { - throw new Error("node1.end !== node2.end"); - } - - if (node1.kind !== node2.kind) { - throw new Error("node1.kind !== node2.kind"); - } - - if (node1.flags !== node2.flags) { - throw new Error("node1.flags !== node2.flags"); - } - - if (node1.parserContextFlags !== node2.parserContextFlags) { - throw new Error("node1.parserContextFlags !== node2.parserContextFlags"); - } + assert(node1, "node1"); + assert(node2, "node2"); + assert.equal(node1.pos, node2.pos, "node1.pos !== node2.pos"); + assert.equal(node1.end, node2.end, "node1.end !== node2.end"); + assert.equal(node1.kind, node2.kind, "node1.kind !== node2.kind"); + assert.equal(node1.flags, node2.flags, "node1.flags !== node2.flags"); + assert.equal(node1.parserContextFlags, node2.parserContextFlags, "node1.parserContextFlags !== node2.parserContextFlags"); forEachChild(node1, child1 => { @@ -104,21 +88,11 @@ module ts { return; } - if (!array1 || !array2) { - throw new Error("!array1 || !array2"); - } - - if (array1.pos !== array2.pos) { - throw new Error("array1.pos !== array2.pos"); - } - - if (array1.end !== array2.end) { - throw new Error("array1.end !== array2.end"); - } - - if (array1.length !== array2.length) { - throw new Error("array1.length !== array2.length"); - } + assert(array1, "array1"); + assert(array2, "array2"); + assert.equal(array1.pos, array2.pos, "array1.pos !== array2.pos"); + assert.equal(array1.end, array2.end, "array1.end !== array2.end"); + assert.equal(array1.length, array2.length, "array1.length !== array2.length"); for (var i = 0, n = array1.length; i < n; i++) { assertStructuralEquals(array1[i], array2[i]);