Skip to content

Commit b277695

Browse files
Merge pull request #1992 from Microsoft/additionalParserChecks
Additional parser checks
2 parents a710902 + 2eb1a21 commit b277695

File tree

1 file changed

+41
-47
lines changed

1 file changed

+41
-47
lines changed

src/compiler/parser.ts

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,8 @@ module ts {
371371
return false;
372372
}
373373

374-
function moveElementEntirelyPastChangeRange(element: IncrementalElement, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
375-
if (element.length) {
374+
function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
375+
if (isArray) {
376376
visitArray(<IncrementalNodeArray>element);
377377
}
378378
else {
@@ -400,6 +400,7 @@ module ts {
400400
}
401401

402402
function visitArray(array: IncrementalNodeArray) {
403+
array._children = undefined;
403404
array.pos += delta;
404405
array.end += delta;
405406

@@ -412,6 +413,7 @@ module ts {
412413
function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {
413414
Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range");
414415
Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range");
416+
Debug.assert(element.pos <= element.end);
415417

416418
// We have an element that intersects the change range in some way. It may have its
417419
// start, or its end (or both) in the changed range. We want to adjust any part
@@ -508,10 +510,11 @@ module ts {
508510
return;
509511

510512
function visitNode(child: IncrementalNode) {
513+
Debug.assert(child.pos <= child.end);
511514
if (child.pos > changeRangeOldEnd) {
512515
// Node is entirely past the change range. We need to move both its pos and
513516
// end, forward or backward appropriately.
514-
moveElementEntirelyPastChangeRange(child, delta, oldText, newText, aggressiveChecks);
517+
moveElementEntirelyPastChangeRange(child, /*isArray:*/ false, delta, oldText, newText, aggressiveChecks);
515518
return;
516519
}
517520

@@ -521,6 +524,7 @@ module ts {
521524
var fullEnd = child.end;
522525
if (fullEnd >= changeStart) {
523526
child.intersectsChange = true;
527+
child._children = undefined;
524528

525529
// Adjust the pos or end (or both) of the intersecting element accordingly.
526530
adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
@@ -531,32 +535,36 @@ module ts {
531535
}
532536

533537
// Otherwise, the node is entirely before the change range. No need to do anything with it.
538+
Debug.assert(fullEnd < changeStart);
534539
}
535540

536541
function visitArray(array: IncrementalNodeArray) {
542+
Debug.assert(array.pos <= array.end);
537543
if (array.pos > changeRangeOldEnd) {
538544
// Array is entirely after the change range. We need to move it, and move any of
539545
// its children.
540-
moveElementEntirelyPastChangeRange(array, delta, oldText, newText, aggressiveChecks);
546+
moveElementEntirelyPastChangeRange(array, /*isArray:*/ true, delta, oldText, newText, aggressiveChecks);
547+
return;
541548
}
542-
else {
543-
// Check if the element intersects the change range. If it does, then it is not
544-
// reusable. Also, we'll need to recurse to see what constituent portions we may
545-
// be able to use.
546-
var fullEnd = array.end;
547-
if (fullEnd >= changeStart) {
548-
array.intersectsChange = true;
549-
550-
// Adjust the pos or end (or both) of the intersecting array accordingly.
551-
adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
552-
for (var i = 0, n = array.length; i < n; i++) {
553-
visitNode(array[i]);
554-
}
549+
550+
// Check if the element intersects the change range. If it does, then it is not
551+
// reusable. Also, we'll need to recurse to see what constituent portions we may
552+
// be able to use.
553+
var fullEnd = array.end;
554+
if (fullEnd >= changeStart) {
555+
array.intersectsChange = true;
556+
array._children = undefined;
557+
558+
// Adjust the pos or end (or both) of the intersecting array accordingly.
559+
adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
560+
for (var i = 0, n = array.length; i < n; i++) {
561+
visitNode(array[i]);
555562
}
556-
// else {
557-
// Otherwise, the array is entirely before the change range. No need to do anything with it.
558-
// }
563+
return;
559564
}
565+
566+
// Otherwise, the array is entirely before the change range. No need to do anything with it.
567+
Debug.assert(fullEnd < changeStart);
560568
}
561569
}
562570

@@ -842,7 +850,7 @@ module ts {
842850
// Much of the time the parser will need the very next node in the array that
843851
// we just returned a node from.So just simply check for that case and move
844852
// forward in the array instead of searching for the node again.
845-
if (current && current.end === position && currentArrayIndex < currentArray.length) {
853+
if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) {
846854
currentArrayIndex++;
847855
current = currentArray[currentArrayIndex];
848856
}
@@ -878,6 +886,7 @@ module ts {
878886

879887
// Recurse into the source file to find the highest node at this position.
880888
forEachChild(sourceFile, visitNode, visitArray);
889+
return;
881890

882891
function visitNode(node: Node) {
883892
if (position >= node.pos && position < node.end) {
@@ -1649,8 +1658,8 @@ module ts {
16491658
return result;
16501659
}
16511660

1652-
function parseListElement<T extends Node>(kind: ParsingContext, parseElement: () => T): T {
1653-
var node = currentNode(kind);
1661+
function parseListElement<T extends Node>(parsingContext: ParsingContext, parseElement: () => T): T {
1662+
var node = currentNode(parsingContext);
16541663
if (node) {
16551664
return <T>consumeNode(node);
16561665
}
@@ -1807,29 +1816,10 @@ module ts {
18071816
case SyntaxKind.InterfaceDeclaration:
18081817
case SyntaxKind.ModuleDeclaration:
18091818
case SyntaxKind.EnumDeclaration:
1810-
1811-
// Keep in sync with isStatement:
1812-
case SyntaxKind.FunctionDeclaration:
1813-
case SyntaxKind.VariableStatement:
1814-
case SyntaxKind.Block:
1815-
case SyntaxKind.IfStatement:
1816-
case SyntaxKind.ExpressionStatement:
1817-
case SyntaxKind.ThrowStatement:
1818-
case SyntaxKind.ReturnStatement:
1819-
case SyntaxKind.SwitchStatement:
1820-
case SyntaxKind.BreakStatement:
1821-
case SyntaxKind.ContinueStatement:
1822-
case SyntaxKind.ForInStatement:
1823-
case SyntaxKind.ForStatement:
1824-
case SyntaxKind.WhileStatement:
1825-
case SyntaxKind.WithStatement:
1826-
case SyntaxKind.EmptyStatement:
1827-
case SyntaxKind.TryStatement:
1828-
case SyntaxKind.LabeledStatement:
1829-
case SyntaxKind.DoStatement:
1830-
case SyntaxKind.DebuggerStatement:
18311819
return true;
18321820
}
1821+
1822+
return isReusableStatement(node);
18331823
}
18341824

18351825
return false;
@@ -1935,9 +1925,13 @@ module ts {
19351925
}
19361926

19371927
function isReusableParameter(node: Node) {
1938-
// TODO: this most likely needs the same initializer check that
1939-
// isReusableVariableDeclaration has.
1940-
return node.kind === SyntaxKind.Parameter;
1928+
if (node.kind !== SyntaxKind.Parameter) {
1929+
return false;
1930+
}
1931+
1932+
// See the comment in isReusableVariableDeclaration for why we do this.
1933+
var parameter = <ParameterDeclaration>node;
1934+
return parameter.initializer === undefined;
19411935
}
19421936

19431937
// Returns true if we should abort parsing.

0 commit comments

Comments
 (0)