Merge pull request #2396 from Microsoft/completionsInIncompleteConstructs

Better completions in incomplete constructs
This commit is contained in:
Daniel Rosenwasser 2015-03-18 14:11:05 -07:00
commit 355dcd11c8
68 changed files with 1039 additions and 133 deletions

View File

@ -620,7 +620,7 @@ module FourSlash {
this.scenarioActions.push('<VerifyCompletionDoesNotContainItem ItemName="' + escapeXmlAttributeValue(symbol) + '" />');
var members = this.getMemberListAtCaret();
if (members.entries.filter(e => e.name === symbol).length !== 0) {
if (members && members.entries.filter(e => e.name === symbol).length !== 0) {
this.raiseError('Member list did contain ' + symbol);
}
}
@ -691,7 +691,12 @@ module FourSlash {
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string) {
var completions = this.getCompletionListAtCaret();
this.assertItemInCompletionList(completions.entries, symbol, text, documentation, kind);
if (completions) {
this.assertItemInCompletionList(completions.entries, symbol, text, documentation, kind);
}
else {
this.raiseError(`No completions at position '${ this.currentCaretPosition }' when looking for '${ symbol }'.`);
}
}
public verifyCompletionListDoesNotContain(symbol: string) {
@ -699,7 +704,7 @@ module FourSlash {
this.scenarioActions.push('<VerifyCompletionDoesNotContainItem ItemName="' + escapeXmlAttributeValue(symbol) + '" />');
var completions = this.getCompletionListAtCaret();
if (completions && completions.entries && completions.entries.filter(e => e.name === symbol).length !== 0) {
if (completions && completions.entries.filter(e => e.name === symbol).length !== 0) {
this.raiseError('Completion list did contain ' + symbol);
}
}

View File

@ -215,11 +215,7 @@ module ts.formatting {
function getStartLineAndCharacterForNode(n: Node, sourceFile: SourceFile): LineAndCharacter {
return sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile));
}
function positionBelongsToNode(candidate: Node, position: number, sourceFile: SourceFile): boolean {
return candidate.end > position || !isCompletedNode(candidate, sourceFile);
}
export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFile): boolean {
if (parent.kind === SyntaxKind.IfStatement && (<IfStatement>parent).elseStatement === child) {
let elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile);
@ -403,128 +399,5 @@ module ts.formatting {
return false;
}
}
/*
* Checks if node ends with 'expectedLastToken'.
* If child at position 'length - 1' is 'SemicolonToken' it is skipped and 'expectedLastToken' is compared with child at position 'length - 2'.
*/
function nodeEndsWith(n: Node, expectedLastToken: SyntaxKind, sourceFile: SourceFile): boolean {
let children = n.getChildren(sourceFile);
if (children.length) {
let last = children[children.length - 1];
if (last.kind === expectedLastToken) {
return true;
}
else if (last.kind === SyntaxKind.SemicolonToken && children.length !== 1) {
return children[children.length - 2].kind === expectedLastToken;
}
}
return false;
}
/*
* This function is always called when position of the cursor is located after the node
*/
function isCompletedNode(n: Node, sourceFile: SourceFile): boolean {
if (n.getFullWidth() === 0) {
return false;
}
switch (n.kind) {
case SyntaxKind.ClassDeclaration:
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.NewExpression:
if (!(<NewExpression>n).arguments) {
return true;
}
// fall through
case SyntaxKind.CallExpression:
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:
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
return false;
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
case SyntaxKind.WhileStatement:
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);
if (hasWhileKeyword) {
return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
}
return isCompletedNode((<DoStatement>n).statement, sourceFile);
default:
return true;
}
}
}
}

View File

@ -2597,8 +2597,9 @@ module ts {
isNewIdentifierLocation = isNewIdentifierDefinitionLocation(previousToken);
/// TODO filter meaning based on the current context
let scopeNode = getScopeNode(previousToken, position, sourceFile);
let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias;
let symbols = typeInfoResolver.getSymbolsInScope(node, symbolMeanings);
let symbols = typeInfoResolver.getSymbolsInScope(scopeNode, symbolMeanings);
getCompletionEntriesFromSymbols(symbols, activeCompletionSession);
}
@ -2613,10 +2614,22 @@ module ts {
return {
isMemberCompletion,
isNewIdentifierLocation,
isBuilder : isNewIdentifierDefinitionLocation, // temporary property used to match VS implementation
isBuilder: isNewIdentifierDefinitionLocation, // temporary property used to match VS implementation
entries: activeCompletionSession.entries
};
/**
* Finds the first node that "embraces" the position, so that one may
* accurately aggregate locals from the closest containing scope.
*/
function getScopeNode(initialToken: Node, position: number, sourceFile: SourceFile) {
var scope = initialToken;
while (scope && !positionBelongsToNode(scope, position, sourceFile)) {
scope = scope.parent;
}
return scope;
}
function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void {
let start = new Date().getTime();
forEach(symbols, symbol => {

View File

@ -59,6 +59,157 @@ module ts {
return start < end;
}
export function positionBelongsToNode(candidate: Node, position: number, sourceFile: SourceFile): boolean {
return candidate.end > position || !isCompletedNode(candidate, sourceFile);
}
export function isCompletedNode(n: Node, sourceFile: SourceFile): boolean {
if (nodeIsMissing(n)) {
return false;
}
switch (n.kind) {
case SyntaxKind.ClassDeclaration:
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.NewExpression:
if (!(<NewExpression>n).arguments) {
return true;
}
// fall through
case SyntaxKind.CallExpression:
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:
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.ElementAccessExpression:
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
return false;
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
case SyntaxKind.WhileStatement:
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);
if (hasWhileKeyword) {
return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
}
return isCompletedNode((<DoStatement>n).statement, sourceFile);
case SyntaxKind.TypeQuery:
return isCompletedNode((<TypeQueryNode>n).exprName, sourceFile);
case SyntaxKind.TypeOfExpression:
case SyntaxKind.DeleteExpression:
case SyntaxKind.VoidExpression:
case SyntaxKind.YieldExpression:
case SyntaxKind.SpreadElementExpression:
let unaryWordExpression = (<TypeOfExpression|DeleteExpression|VoidExpression|YieldExpression|SpreadElementExpression>n);
return isCompletedNode(unaryWordExpression.expression, sourceFile);
case SyntaxKind.TaggedTemplateExpression:
return isCompletedNode((<TaggedTemplateExpression>n).template, sourceFile);
case SyntaxKind.TemplateExpression:
let lastSpan = lastOrUndefined((<TemplateExpression>n).templateSpans);
return isCompletedNode(lastSpan, sourceFile);
case SyntaxKind.TemplateSpan:
return nodeIsPresent((<TemplateSpan>n).literal);
case SyntaxKind.PrefixUnaryExpression:
return isCompletedNode((<PrefixUnaryExpression>n).operand, sourceFile);
case SyntaxKind.BinaryExpression:
return isCompletedNode((<BinaryExpression>n).right, sourceFile);
case SyntaxKind.ConditionalExpression:
return isCompletedNode((<ConditionalExpression>n).whenFalse, sourceFile);
default:
return true;
}
}
/*
* Checks if node ends with 'expectedLastToken'.
* If child at position 'length - 1' is 'SemicolonToken' it is skipped and 'expectedLastToken' is compared with child at position 'length - 2'.
*/
function nodeEndsWith(n: Node, expectedLastToken: SyntaxKind, sourceFile: SourceFile): boolean {
let children = n.getChildren(sourceFile);
if (children.length) {
let last = children[children.length - 1];
if (last.kind === expectedLastToken) {
return true;
}
else if (last.kind === SyntaxKind.SemicolonToken && children.length !== 1) {
return children[children.length - 2].kind === expectedLastToken;
}
}
return false;
}
export function findListItemInfo(node: Node): ListItemInfo {
let list = findContainingList(node);

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
/////*1*/
////var x = 0, y = 1, z = 2;
////enum E {
//// A, B, C
////}
goTo.marker("1");
verify.completionListContains("x");
verify.completionListContains("y");
verify.completionListContains("z");
verify.completionListContains("E");

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////p/*1*/
////
////function fun(param) {
//// let party = Math.random() < 0.99;
////}
goTo.marker("1");
verify.not.completionListContains("param");
verify.not.completionListContains("party");

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////a/*1*/
////
////{
//// let aaaaaa = 10;
////}
goTo.marker("1");
verify.not.completionListContains("aaaaa");

View File

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
////declare function foo(...params: any[]): any;
////function getAllFiles(rootFileNames: string[]) {
//// var processedFiles = rootFileNames.map(fileName => foo(/*1*/
goTo.marker("1");
verify.completionListContains("fileName");
verify.completionListContains("rootFileNames");
verify.completionListContains("getAllFiles");
verify.completionListContains("foo");

View File

@ -0,0 +1,12 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// /*1*/
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof /*1*/) {
//// }
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // questionable

View File

@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof x = /*1*/) {
////
//// }
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // questionable

View File

@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = /*1*/, c: typeof x = "hello") {
////
//// }
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // definitely questionable

View File

@ -0,0 +1,21 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = /*1*/
//// }
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v"); // questionable

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (x: /*1*/);
//// }
////}
goTo.marker("1");
verify.memberListContains("MyType");

View File

@ -0,0 +1,25 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: MyType) => /*1*/;
//// }
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v");
verify.memberListContains("p");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { str: T/*1*/ }
goTo.marker("1");
verify.memberListContains("I");
verify.memberListContains("TString");
verify.memberListContains("TNumber");
// Ideally the following shouldn't show up since they're not types.
verify.memberListContains("foo");
verify.memberListContains("obj");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { str: TStr/*1*/ }
goTo.marker("1");
verify.memberListContains("I");
verify.memberListContains("TString");
verify.memberListContains("TNumber"); // REVIEW: Is this intended behavior?
// Ideally the following shouldn't show up since they're not types.
verify.memberListContains("foo");
verify.memberListContains("obj");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { str: TString/*1*/ }
goTo.marker("1");
verify.memberListContains("I");
verify.memberListContains("TString");
verify.memberListContains("TNumber"); // REVIEW: Is this intended behavior?
// Ideally the following shouldn't show up since they're not types.
verify.memberListContains("foo");
verify.memberListContains("obj");

View File

@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { /*1*/ }
goTo.marker("1");
verify.not.memberListContains("I");
verify.not.memberListContains("TString");
verify.not.memberListContains("TNumber");
verify.not.memberListContains("foo");
verify.not.memberListContains("obj");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////// should NOT see a and b
////foo((a, b) => a,/*1*/
goTo.marker("1");
verify.not.completionListContains("a");
verify.not.completionListContains("b");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////// should NOT see a and b
////foo((a, b) => (a,/*1*/
goTo.marker("1");
verify.completionListContains("a");
verify.completionListContains("b");

View File

@ -0,0 +1,7 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = delete /*1*/
goTo.marker("1");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => delete /*1*/
goTo.marker("1");
verify.completionListContains("x");
verify.completionListContains("p");

View File

@ -0,0 +1,7 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = x[/*1*/
goTo.marker("1");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => x[/*1*/
goTo.marker("1");
verify.completionListContains("p");
verify.completionListContains("x");

View File

@ -0,0 +1,6 @@
/// <reference path='fourslash.ts' />
////for (let i = 0; /*1*/
goTo.marker("1");
verify.completionListContains("i");

View File

@ -0,0 +1,6 @@
/// <reference path='fourslash.ts' />
////for (let i = 0; i < 10; i++) /*1*/
goTo.marker("1");
verify.completionListContains("i");

View File

@ -0,0 +1,12 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// /*1*/
////
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");

View File

@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof /*1*/
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // questionable

View File

@ -0,0 +1,17 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof /*1*/
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // questionable

View File

@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof x = /*1*/
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // questionable

View File

@ -0,0 +1,17 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string, c: typeof x = /*1*/
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // questionable

View File

@ -0,0 +1,17 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = /*1*/, c: typeof x = "hello"
////
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // definitely questionable

View File

@ -0,0 +1,17 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = /*1*/, c: typeof x = "hello"
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c"); // definitely questionable

View File

@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = /*1*/
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v"); // questionable

View File

@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = /*1*/
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v"); // questionable

View File

@ -0,0 +1,12 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: /*1*/
goTo.marker("1");
verify.memberListContains("MyType");

View File

@ -0,0 +1,12 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: /*1*/
goTo.marker("1");
verify.memberListContains("MyType");

View File

@ -0,0 +1,13 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: /*1*/
////}
goTo.marker("1");
verify.memberListContains("MyType");

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: /*1*/
//// }
////}
goTo.marker("1");
verify.memberListContains("MyType");

View File

@ -0,0 +1,25 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: MyType) => /*1*/
//// }
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v");
verify.memberListContains("p");

View File

@ -0,0 +1,24 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: MyType) => /*1*/
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v");
verify.memberListContains("p");

View File

@ -0,0 +1,23 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: MyType) => /*1*/
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v");
verify.memberListContains("p");

View File

@ -0,0 +1,23 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: MyType) => y + /*1*/
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v");
verify.memberListContains("p");

View File

@ -0,0 +1,24 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: MyType) => y + /*1*/
////}
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v");
verify.memberListContains("p");

View File

@ -0,0 +1,23 @@
/// <reference path="fourslash.ts" />
////interface MyType {
////}
////
////function foo(x: string, y: number, z: boolean) {
//// function bar(a: number, b: string = "hello", c: typeof x = "hello") {
//// var v = (p: MyType) => { return y + /*1*/
goTo.marker("1");
verify.memberListContains("foo");
verify.memberListContains("x");
verify.memberListContains("y");
verify.memberListContains("z");
verify.memberListContains("bar");
verify.memberListContains("a");
verify.memberListContains("b");
verify.memberListContains("c");
verify.memberListContains("v");
verify.memberListContains("p");

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////class C {
//// [foo: string]: typeof /*1*/
////}
goTo.marker("1");
verify.completionListContains("foo");
verify.completionListContains("C");

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
////class C {
//// [foo: /*1*/
////}
goTo.marker("1");
verify.completionListContains("C");
verify.completionListContains("foo"); // ideally this shouldn't show up for a type
edit.insert("typeof ");
verify.completionListContains("C");
verify.completionListContains("foo");

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////class C {
//// [foo: string]: { x: typeof /*1*/
////}
goTo.marker("1");
verify.completionListContains("foo");
verify.completionListContains("C");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { str: T/*1*/
goTo.marker("1");
verify.memberListContains("I");
verify.memberListContains("TString");
verify.memberListContains("TNumber");
// Ideally the following shouldn't show up since they're not types.
verify.memberListContains("foo");
verify.memberListContains("obj");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { str: TStr/*1*/
goTo.marker("1");
verify.memberListContains("I");
verify.memberListContains("TString");
verify.memberListContains("TNumber"); // REVIEW: Is this intended behavior?
// Ideally the following shouldn't show up since they're not types.
verify.memberListContains("foo");
verify.memberListContains("obj");

View File

@ -0,0 +1,18 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { str: TString/*1*/
goTo.marker("1");
verify.memberListContains("I");
verify.memberListContains("TString");
verify.memberListContains("TNumber"); // REVIEW: Is this intended behavior?
// Ideally the following shouldn't show up since they're not types.
verify.memberListContains("foo");
verify.memberListContains("obj");

View File

@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />
////interface I<TString, TNumber> {
//// [s: string]: TString;
//// [s: number]: TNumber;
////}
////
////declare function foo<TString, TNumber>(obj: I<TString, TNumber>): { /*1*/
goTo.marker("1");
verify.not.memberListContains("I");
verify.not.memberListContains("TString");
verify.not.memberListContains("TNumber");
verify.not.memberListContains("foo");
verify.not.memberListContains("obj");

View File

@ -0,0 +1,7 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = [1,2,.../*1*/
goTo.marker("1");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => [1,2,.../*1*/
goTo.marker("1");
verify.completionListContains("p");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => x `abc ${ /*1*/
goTo.marker("1");
verify.completionListContains("p");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => x `abc ${ 123 } ${ /*1*/
goTo.marker("1");
verify.completionListContains("p");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => `abc ${ /*1*/
goTo.marker("1");
verify.completionListContains("p");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => `abc ${ 123 } ${ /*1*/
goTo.marker("1");
verify.completionListContains("p");
verify.completionListContains("x");

View File

@ -0,0 +1,7 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = typeof /*1*/
goTo.marker("1");
verify.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => typeof /*1*/
goTo.marker("1");
verify.completionListContains("x");
verify.completionListContains("p");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = (p) => void /*1*/
goTo.marker("1");
verify.completionListContains("p");
verify.completionListContains("x");

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
////var x;
////var y = function* gen(p) { yield /*1*/
goTo.marker("1");
// These tentatively don't work.
verify.not.completionListContains("p");
verify.not.completionListContains("gen");
verify.not.completionListContains("x");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////// no a or b
/////*1*/(a, b) => { }
goTo.marker("1");
verify.not.completionListContains("a");
verify.not.completionListContains("b");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////// no a or b
////(a, b) => { }/*1*/
goTo.marker("1");
verify.not.completionListContains("a");
verify.not.completionListContains("b");

View File

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
////// no a or b
/////*1*/function f (a, b) {}
goTo.marker("1");
verify.not.completionListContains("a");
verify.not.completionListContains("b");

View File

@ -0,0 +1,6 @@
/// <reference path='fourslash.ts' />
////for (let i = 0; i < 10; i++) i;/*1*/
goTo.marker("1");
verify.not.completionListContains("i");

View File

@ -0,0 +1,6 @@
/// <reference path='fourslash.ts' />
////for (let i = 0; i < 10; i++);/*1*/
goTo.marker("1");
verify.not.completionListContains("i");