Merge pull request #2385 from Microsoft/completeIsCompleteNode

More thorough node completed-ness checking
This commit is contained in:
Daniel Rosenwasser
2015-03-17 11:35:26 -07:00
27 changed files with 375 additions and 17 deletions

View File

@@ -1621,8 +1621,9 @@ module FourSlash {
this.taoInvalidReason = 'verifyIndentationAtCurrentPosition NYI';
var actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition);
if (actual != numberOfSpaces) {
this.raiseError('verifyIndentationAtCurrentPosition failed - expected: ' + numberOfSpaces + ', actual: ' + actual);
var lineCol = this.getLineColStringAtPosition(this.currentCaretPosition);
if (actual !== numberOfSpaces) {
this.raiseError('verifyIndentationAtCurrentPosition failed at ' + lineCol + ' - expected: ' + numberOfSpaces + ', actual: ' + actual);
}
}
@@ -1630,8 +1631,9 @@ module FourSlash {
this.taoInvalidReason = 'verifyIndentationAtPosition NYI';
var actual = this.getIndentation(fileName, position);
var lineCol = this.getLineColStringAtPosition(position);
if (actual !== numberOfSpaces) {
this.raiseError('verifyIndentationAtPosition failed - expected: ' + numberOfSpaces + ', actual: ' + actual);
this.raiseError('verifyIndentationAtPosition failed at ' + lineCol + ' - expected: ' + numberOfSpaces + ', actual: ' + actual);
}
}

View File

@@ -359,6 +359,7 @@ module ts.formatting {
case SyntaxKind.ModuleBlock:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.TypeLiteral:
case SyntaxKind.TupleType:
case SyntaxKind.CaseBlock:
case SyntaxKind.DefaultClause:
case SyntaxKind.CaseClause:
@@ -370,6 +371,8 @@ module ts.formatting {
case SyntaxKind.ExportAssignment:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.ArrayBindingPattern:
case SyntaxKind.ObjectBindingPattern:
return true;
}
return false;
@@ -390,6 +393,7 @@ module ts.formatting {
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.ArrowFunction:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
@@ -431,46 +435,85 @@ module ts.formatting {
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.TypeLiteral:
case SyntaxKind.Block:
case SyntaxKind.ModuleBlock:
case SyntaxKind.CaseBlock:
return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile);
case SyntaxKind.CatchClause:
return isCompletedNode((<CatchClause>n).block, sourceFile);
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.CallSignature:
case SyntaxKind.NewExpression:
if (!(<NewExpression>n).arguments) {
return true;
}
// fall through
case SyntaxKind.CallExpression:
case SyntaxKind.ConstructSignature:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.ParenthesizedType:
return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
return isCompletedNode((<SignatureDeclaration>n).type, sourceFile);
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.ArrowFunction:
return !(<FunctionLikeDeclaration>n).body || isCompletedNode((<FunctionLikeDeclaration>n).body, sourceFile);
if ((<FunctionLikeDeclaration>n).body) {
return isCompletedNode((<FunctionLikeDeclaration>n).body, sourceFile);
}
if ((<FunctionLikeDeclaration>n).type) {
return isCompletedNode((<FunctionLikeDeclaration>n).type, sourceFile);
}
// Even though type parameters can be unclosed, we can get away with
// having at least a closing paren.
return hasChildOfKind(n, SyntaxKind.CloseParenToken, sourceFile);
case SyntaxKind.ModuleDeclaration:
return (<ModuleDeclaration>n).body && isCompletedNode((<ModuleDeclaration>n).body, sourceFile);
case SyntaxKind.IfStatement:
if ((<IfStatement>n).elseStatement) {
return isCompletedNode((<IfStatement>n).elseStatement, sourceFile);
}
return isCompletedNode((<IfStatement>n).thenStatement, sourceFile);
case SyntaxKind.ExpressionStatement:
return isCompletedNode((<ExpressionStatement>n).expression, sourceFile);
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.ArrayBindingPattern:
case SyntaxKind.ComputedPropertyName:
case SyntaxKind.TupleType:
return nodeEndsWith(n, SyntaxKind.CloseBracketToken, sourceFile);
case SyntaxKind.IndexSignature:
if ((<IndexSignatureDeclaration>n).type) {
return isCompletedNode((<IndexSignatureDeclaration>n).type, sourceFile);
}
return hasChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
case SyntaxKind.CaseClause:
case SyntaxKind.DefaultClause:
// there is no such thing as terminator token for CaseClause\DefaultClause so for simplicitly always consider them non-completed
// there is no such thing as terminator token for CaseClause/DefaultClause so for simplicitly always consider them non-completed
return false;
case SyntaxKind.ForStatement:
return isCompletedNode((<ForStatement>n).statement, sourceFile);
case SyntaxKind.ForInStatement:
return isCompletedNode((<ForInStatement>n).statement, sourceFile);
case SyntaxKind.ForOfStatement:
return isCompletedNode((<ForOfStatement>n).statement, sourceFile);
case SyntaxKind.WhileStatement:
return isCompletedNode((<WhileStatement>n).statement, sourceFile);
return isCompletedNode((<IterationStatement>n).statement, sourceFile);
case SyntaxKind.DoStatement:
// rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')';
let hasWhileKeyword = findChildOfKind(n, SyntaxKind.WhileKeyword, sourceFile);
@@ -478,6 +521,7 @@ module ts.formatting {
return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
}
return isCompletedNode((<DoStatement>n).statement, sourceFile);
default:
return true;
}

View File

@@ -79,6 +79,10 @@ module ts {
};
}
export function hasChildOfKind(n: Node, kind: SyntaxKind, sourceFile?: SourceFile): boolean {
return !!findChildOfKind(n, kind, sourceFile);
}
export function findChildOfKind(n: Node, kind: SyntaxKind, sourceFile?: SourceFile): Node {
return forEach(n.getChildren(sourceFile), c => c.kind === kind && c);
}

View File

@@ -176,8 +176,8 @@
////// the purpose of this test is to verity smart indent
////// works for unterminated function arguments at the end of a file.
////function unterminatedListIndentation(a,
////{| "indent": 0 |}
////{| "indent": 4 |}
test.markers().forEach((marker) => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,17 @@
/// <reference path="fourslash.ts"/>
////
////new Array
////{| "indent": 0 |}
////new Array;
////{| "indent": 0 |}
////new Array(0);
////{| "indent": 0 |}
////new Array(;
////{| "indent": 0 |}
////new Array(
////{| "indent": 4 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,14 @@
/// <reference path="fourslash.ts"/>
////var /*1*/[/*2*/a,/*3*/b,/*4*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 8);
verifyIndentationAfterNewLine("3", 8);
verifyIndentationAfterNewLine("4", 8);

View File

@@ -0,0 +1,15 @@
/// <reference path="fourslash.ts"/>
////var /*1*/[/*2*/a,/*3*/b/*4*/]/*5*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 8);
verifyIndentationAfterNewLine("3", 8);
verifyIndentationAfterNewLine("4", 8);
verifyIndentationAfterNewLine("5", 0);

View File

@@ -0,0 +1,13 @@
/// <reference path="fourslash.ts"/>
////var x = (/*1*/1/*2*/)/*3*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 4);
verifyIndentationAfterNewLine("3", 0);

View File

@@ -0,0 +1,8 @@
/// <reference path="fourslash.ts"/>
////var y = (
////{| "indent": 4 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -4,4 +4,4 @@
/////**/
goTo.marker();
verify.indentationIs(0);
verify.indentationIs(4);

View File

@@ -0,0 +1,15 @@
/// <reference path="fourslash.ts"/>
////var /*1*/{/*2*/a,/*3*/b:/*4*/k,/*5*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 8);
verifyIndentationAfterNewLine("3", 8);
verifyIndentationAfterNewLine("4", 8);
verifyIndentationAfterNewLine("5", 8);

View File

@@ -0,0 +1,16 @@
/// <reference path="fourslash.ts"/>
////var /*1*/{/*2*/a,/*3*/b:/*4*/k,/*5*/}/*6*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 8);
verifyIndentationAfterNewLine("3", 8);
verifyIndentationAfterNewLine("4", 8);
verifyIndentationAfterNewLine("5", 8);
verifyIndentationAfterNewLine("6", 0);

View File

@@ -0,0 +1,36 @@
/// <reference path='fourslash.ts' />
////class Foo {
//// get foo(a,
//// /*1*/b,/*0*/
//// //comment/*2*/
//// /*3*/c
//// ) {
//// }
//// set foo(a,
//// /*5*/b,/*4*/
//// //comment/*6*/
//// /*7*/c
//// ) {
//// }
////}
goTo.marker("0");
edit.insert("\r\n");
verify.indentationIs(8);
goTo.marker("1");
verify.currentLineContentIs(" b,");
goTo.marker("2");
verify.currentLineContentIs(" //comment");
goTo.marker("3");
verify.currentLineContentIs(" c");
goTo.marker("4");
edit.insert("\r\n");
verify.indentationIs(8);
goTo.marker("5");
verify.currentLineContentIs(" b,");
goTo.marker("6");
verify.currentLineContentIs(" //comment");
goTo.marker("7");
verify.currentLineContentIs(" c");

View File

@@ -0,0 +1,36 @@
/// <reference path='fourslash.ts' />
////class Foo {
//// get foo(a,
//// /*1*/b,/*0*/
//// //comment/*2*/
//// /*3*/c
//// ) {
//// }
//// set foo(a,
//// /*5*/b,/*4*/
//// //comment/*6*/
//// /*7*/c
//// ) {
//// }
////}
goTo.marker("0");
edit.insert("\r\n");
verify.indentationIs(8);
goTo.marker("1");
verify.currentLineContentIs(" b,");
goTo.marker("2");
verify.currentLineContentIs(" //comment");
goTo.marker("3");
verify.currentLineContentIs(" c");
goTo.marker("4");
edit.insert("\r\n");
verify.indentationIs(8);
goTo.marker("5");
verify.currentLineContentIs(" b,");
goTo.marker("6");
verify.currentLineContentIs(" //comment");
goTo.marker("7");
verify.currentLineContentIs(" c");

View File

@@ -0,0 +1,9 @@
/// <reference path='fourslash.ts' />
////class Foo {
//// get foo() {
////{| "indent": 8 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x: () => {
////{| "indent": 4 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////var x = {
//// [1123123123132
////{| "indent": 4 |}
////}
// Note that we currently do NOT indent further in a computed property.
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x: new () => {
////{| "indent": 4 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
////function /*1*/f/*2*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 4);

View File

@@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
////function f</*1*/A/*2*/,B/*3*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 4);
verifyIndentationAfterNewLine("3", 4);

View File

@@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
////function f<A,B,C>/*1*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);

View File

@@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />
////function f<A,B,C>/*1*/(/*2*/a: A, /*3*/b:/*4*/B, c/*5*/, d: C/*6*/
function verifyIndentationAfterNewLine(marker: string, indentation: number): void {
goTo.marker(marker);
edit.insert("\r\n");
verify.indentationIs(indentation);
}
verifyIndentationAfterNewLine("1", 4);
verifyIndentationAfterNewLine("2", 4);
verifyIndentationAfterNewLine("3", 4);
verifyIndentationAfterNewLine("4", 4);
verifyIndentationAfterNewLine("5", 4);
verifyIndentationAfterNewLine("6", 4);

View File

@@ -0,0 +1,9 @@
/// <reference path='fourslash.ts' />
////function f<A,B,C>(a: A, b:B, c, d: C): {
////{| "indent": 4 |}
////
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////function f<A,B,C>(a: A, b:B, c, d: C): {
////{| "indent": 4 |}
////} {
////{| "indent": 4 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////class C {
////[x: string
////{| "indent": 4 |}
////
// Note that we currently do NOT indent further in an index signature.
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x: {
////{| "indent": 4 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});

View File

@@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x: [string, number,
////{| "indent": 4 |}
test.markers().forEach(marker => {
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
});