Skip to content

Tagged Template Signature Help Support in Language Service #1204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Nov 25, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1532f72
Initial signature help work for tagged templates.
DanielRosenwasser Nov 11, 2014
d951388
Merge branch 'master' into taggedSigHelp
DanielRosenwasser Nov 12, 2014
0a6dbe3
Merge branch 'master' into taggedSigHelp
DanielRosenwasser Nov 12, 2014
15560a8
Stylistic changes/comment fixups.
DanielRosenwasser Nov 13, 2014
4bf0239
Merge branch 'master' into taggedSigHelp
DanielRosenwasser Nov 14, 2014
64960cf
Got sig help working in the template head.
DanielRosenwasser Nov 15, 2014
6f8f79e
Got sig help working in tagged no-sub templates.
DanielRosenwasser Nov 15, 2014
c79c124
Merge branch 'master' into taggedSigHelp
DanielRosenwasser Nov 17, 2014
34087bd
Refactored code, adjusted for residing out of bounds of the template.
DanielRosenwasser Nov 17, 2014
0416c6f
Fixed isUnclosedTemplateLiteral to account for new possible inputs.
DanielRosenwasser Nov 17, 2014
fb91a51
Merge branch 'master' into taggedSigHelp
DanielRosenwasser Nov 18, 2014
69f7d39
Fixed template head offsetting.
DanielRosenwasser Nov 18, 2014
4e18efd
Tests for signature help on tagged templates with no overloads.
DanielRosenwasser Nov 18, 2014
dfe7962
Added tests for overloads.
DanielRosenwasser Nov 19, 2014
7808238
Merge branch 'master' into taggedSigHelp
DanielRosenwasser Nov 19, 2014
513a8c3
Fixed broken test.
DanielRosenwasser Nov 19, 2014
b98f6b4
Paramter -> Parameter
DanielRosenwasser Nov 19, 2014
db69ec1
getCallLikeInvoker -> getInvokedExpression
DanielRosenwasser Nov 19, 2014
0404e84
Addressed some CR feedback.
DanielRosenwasser Nov 21, 2014
7211dfa
Added test.
DanielRosenwasser Nov 21, 2014
a71c527
Amended comment.
DanielRosenwasser Nov 21, 2014
1bbb034
Addressed CR feedback.
DanielRosenwasser Nov 25, 2014
ad39bdf
Merge branch 'master' into taggedSigHelp
DanielRosenwasser Nov 25, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,15 @@ module ts {
}
}

export function getInvokedExpression(node: CallLikeExpression): Expression {
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
return (<TaggedTemplateExpression>node).tag;
}

// Will either be a CallExpression or NewExpression.
return (<CallExpression>node).func;
}

export function isExpression(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.ThisKeyword:
Expand Down Expand Up @@ -801,14 +810,19 @@ module ts {
}

export function isUnterminatedTemplateEnd(node: LiteralExpression) {
Debug.assert(node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail);
Debug.assert(isTemplateLiteralKind(node.kind));
var sourceText = getSourceFileOfNode(node).text;

// If we're not at the EOF, we know we must be terminated.
if (node.end !== sourceText.length) {
return false;
}

// The literal can only be unterminated if it is a template tail or a no-sub template.
if (node.kind !== SyntaxKind.TemplateTail && node.kind !== SyntaxKind.NoSubstitutionTemplateLiteral) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you mean unclosed in this context?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should probably be more explicit - it kind of sounds like I'm referring to a template expression without a template tail. I really mean unterminated, in the sense that your literal isn't explicitly sealed off with a backtick. I'll clarify it. Thanks!

return false;
}

// If we didn't end in a backtick, we must still be in the middle of a template.
// If we did, make sure that it's not the *initial* backtick.
return sourceText.charCodeAt(node.end - 1) !== CharacterCodes.backtick || node.text.length === 0;
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ module ts {
getAugmentedPropertiesOfType(type: Type): Symbol[];
getRootSymbols(symbol: Symbol): Symbol[];
getContextualType(node: Node): Type;
getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature;
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature;
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature;
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
isUndefinedSymbol(symbol: Symbol): boolean;
Expand Down
289 changes: 212 additions & 77 deletions src/services/signatureHelp.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,4 +320,9 @@ module ts {
export function isPunctuation(kind: SyntaxKind): boolean {
return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation;
}

export function isInsideTemplateLiteral(node: LiteralExpression, position: number) {
return (node.getStart() < position && position < node.getEnd())
|| (isUnterminatedTemplateEnd(node) && position === node.getEnd());
}
}
4 changes: 2 additions & 2 deletions tests/cases/fourslash/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,11 @@ module FourSlashInterface {
FourSlash.currentTestState.verifySignatureHelpArgumentCount(expected);
}

public currentSignatureParamterCountIs(expected: number) {
public currentSignatureParameterCountIs(expected: number) {
FourSlash.currentTestState.verifyCurrentSignatureHelpParameterCount(expected);
}

public currentSignatureTypeParamterCountIs(expected: number) {
public currentSignatureTypeParameterCountIs(expected: number) {
FourSlash.currentTestState.verifyCurrentSignatureHelpTypeParameterCount(expected);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/genericParameterHelp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
////testFunction<, ,/*5*/>(null, null, null);

// goTo.marker("1");
// verify.currentSignatureParamterCountIs(3);
// verify.currentSignatureParameterCountIs(3);
// verify.currentSignatureHelpIs("testFunction<T extends IFoo, U, M extends IFoo>(a: T, b: U, c: M): M");

// verify.currentParameterHelpArgumentNameIs("T");
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpAnonymousFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

goTo.marker('anonymousFunction1');
verify.signatureHelpCountIs(1);
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentSignatureHelpIs('(a: number, b: string): string');
verify.currentParameterHelpArgumentNameIs("a");
verify.currentParameterSpanIs("a: number");
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpAtEOF.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ verify.signatureHelpPresent();
verify.signatureHelpCountIs(1);

verify.currentSignatureHelpIs("Foo(arg1: string, arg2: string): void");
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentParameterHelpArgumentNameIs("arg1");
verify.currentParameterSpanIs("arg1: string");
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpBeforeSemicolon1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ verify.signatureHelpPresent();
verify.signatureHelpCountIs(1);

verify.currentSignatureHelpIs("Foo(arg1: string, arg2: string): void");
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentParameterHelpArgumentNameIs("arg1");
verify.currentParameterSpanIs("arg1: string");
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpCallExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

goTo.marker('1');
verify.signatureHelpCountIs(1);
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentSignatureHelpIs('fnTest(str: string, num: number): void');

verify.currentParameterHelpArgumentNameIs('str');
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpConstructExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
goTo.marker('1');
verify.signatureHelpCountIs(1);

verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentSignatureHelpIs('sampleCls(str: string, num: number): sampleCls');

verify.currentParameterHelpArgumentNameIs('str');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

goTo.marker('indirectSuperCall');
verify.signatureHelpCountIs(2);
verify.currentSignatureParamterCountIs(1);
verify.currentSignatureParameterCountIs(1);
verify.currentSignatureHelpIs('B2(n: number): B2');
verify.currentParameterHelpArgumentNameIs("n");
verify.currentParameterSpanIs("n: number");
4 changes: 2 additions & 2 deletions tests/cases/fourslash/signatureHelpConstructorOverload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

goTo.marker('1');
verify.signatureHelpCountIs(2);
verify.currentSignatureParamterCountIs(0);
verify.currentSignatureParameterCountIs(0);
verify.currentSignatureHelpIs('clsOverload(): clsOverload');

goTo.marker('2');
verify.currentSignatureParamterCountIs(1);
verify.currentSignatureParameterCountIs(1);
verify.currentSignatureHelpIs('clsOverload(test: string): clsOverload');
verify.currentParameterHelpArgumentNameIs('test');
verify.currentParameterSpanIs("test: string");
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpEmptyList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ verify.signatureHelpPresent();
verify.signatureHelpCountIs(1);

verify.currentSignatureHelpIs("Foo(arg1: string, arg2: string): void");
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentParameterHelpArgumentNameIs("arg1");
verify.currentParameterSpanIs("arg1: string");

Expand Down
4 changes: 2 additions & 2 deletions tests/cases/fourslash/signatureHelpFunctionOverload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

goTo.marker('functionOverload1');
verify.signatureHelpCountIs(2);
verify.currentSignatureParamterCountIs(0);
verify.currentSignatureParameterCountIs(0);
verify.currentSignatureHelpIs('functionOverload(): any');

goTo.marker('functionOverload2');
verify.currentSignatureParamterCountIs(1);
verify.currentSignatureParameterCountIs(1);
verify.currentSignatureHelpIs('functionOverload(test: string): any');
verify.currentParameterHelpArgumentNameIs("test");
verify.currentParameterSpanIs("test: string");
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpFunctionParameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

goTo.marker('parameterFunction1');
verify.signatureHelpCountIs(1);
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentSignatureHelpIs('callback(a: number, b: string): void');
verify.currentParameterHelpArgumentNameIs("a");
verify.currentParameterSpanIs("a: number");
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/signatureHelpImplicitConstructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
goTo.marker();
verify.signatureHelpCountIs(1);
verify.currentSignatureHelpIs("ImplicitConstructor(): ImplicitConstructor");
verify.currentSignatureParamterCountIs(0);
verify.currentSignatureParameterCountIs(0);
6 changes: 3 additions & 3 deletions tests/cases/fourslash/signatureHelpIncompleteCalls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

goTo.marker('incompleteCalls1');
verify.currentSignatureHelpIs("f1(): void");
verify.currentSignatureParamterCountIs(0);
verify.currentSignatureParameterCountIs(0);

goTo.marker('incompleteCalls2');
verify.currentSignatureParamterCountIs(1);
verify.currentSignatureParameterCountIs(1);
verify.currentSignatureHelpIs("f2(n: number): number");
goTo.marker('incompleteCalls3');
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentSignatureHelpIs("f3(n: number, s: string): string");

verify.currentParameterHelpArgumentNameIs("s");
Expand Down
24 changes: 12 additions & 12 deletions tests/cases/fourslash/signatureHelpObjectLiteral.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
/// <reference path='fourslash.ts' />

////var objectLiteral = { n: 5, s: "", f: (a: number, b: string) => "" };
////objectLiteral.f(/*objectLiteral1*/4, /*objectLiteral2*/"");

goTo.marker('objectLiteral1');
verify.signatureHelpCountIs(1);
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureHelpIs('f(a: number, b: string): string');

verify.currentParameterHelpArgumentNameIs("a");
verify.currentParameterSpanIs("a: number");

goTo.marker('objectLiteral2');
verify.currentSignatureHelpIs('f(a: number, b: string): string');
////objectLiteral.f(/*objectLiteral1*/4, /*objectLiteral2*/"");
goTo.marker('objectLiteral1');
verify.signatureHelpCountIs(1);
verify.currentSignatureParameterCountIs(2);
verify.currentSignatureHelpIs('f(a: number, b: string): string');
verify.currentParameterHelpArgumentNameIs("a");
verify.currentParameterSpanIs("a: number");
goTo.marker('objectLiteral2');
verify.currentSignatureHelpIs('f(a: number, b: string): string');
verify.currentParameterHelpArgumentNameIs("b");
verify.currentParameterSpanIs("b: string");
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@
goTo.marker();
verify.signatureHelpCountIs(4);
verify.currentSignatureHelpIs("f(): any");
verify.currentSignatureParamterCountIs(0);
verify.currentSignatureParameterCountIs(0);
verify.signatureHelpArgumentCountIs(0);

edit.insert(", ");
verify.signatureHelpCountIs(4);
verify.currentSignatureHelpIs("f(s: string, b: boolean): any");
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
verify.currentParameterHelpArgumentNameIs("b");
verify.currentParameterSpanIs("b: boolean");

edit.insert(", ");
verify.signatureHelpCountIs(4);
verify.currentSignatureHelpIs("f(s: string, b: boolean): any");
verify.currentSignatureParamterCountIs(2);
verify.currentSignatureParameterCountIs(2);
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
goTo.marker('superOverload1');
verify.signatureHelpCountIs(2);
verify.currentSignatureHelpIs("SuperOverloadlBase(): SuperOverloadlBase");
verify.currentSignatureParamterCountIs(0);
verify.currentSignatureParameterCountIs(0);
goTo.marker('superOverload2');
verify.currentSignatureParamterCountIs(1);
verify.currentSignatureParameterCountIs(1);
verify.currentSignatureHelpIs("SuperOverloadlBase(test: string): SuperOverloadlBase");
verify.currentParameterHelpArgumentNameIs("test");
verify.currentParameterSpanIs("test: string");
18 changes: 18 additions & 0 deletions tests/cases/fourslash/signatureHelpTaggedTemplates1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />

//// function f(templateStrings, x, y, z) { return 10; }
//// function g(templateStrings, x, y, z) { return ""; }
////
//// f `/*1*/ qwe/*2*/rty /*3*/$/*4*/{ 123 }/*5*/ as/*6*/df /*7*/$/*8*/{ 41234 }/*9*/ zxc/*10*/vb /*11*/$/*12*/{ g ` ` }/*13*/ /*14*/ /*15*/`

test.markers().forEach(m => {
goTo.position(m.position);

verify.signatureHelpCountIs(1);
verify.signatureHelpArgumentCountIs(4);

verify.currentSignatureParameterCountIs(4);
verify.currentSignatureHelpIs('f(templateStrings: any, x: any, y: any, z: any): number');
verify.currentParameterHelpArgumentNameIs("templateStrings");
verify.currentParameterSpanIs("templateStrings: any");
});
18 changes: 18 additions & 0 deletions tests/cases/fourslash/signatureHelpTaggedTemplates2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />

//// function f(templateStrings, x, y, z) { return 10; }
//// function g(templateStrings, x, y, z) { return ""; }
////
//// f `/*1*/ qwe/*2*/rty /*3*/$/*4*/{ 123 }/*5*/ as/*6*/df /*7*/$/*8*/{ 41234 }/*9*/ zxc/*10*/vb /*11*/$/*12*/{ g ` ` }/*13*/ /*14*/ /*15*/

test.markers().forEach(m => {
goTo.position(m.position);

verify.signatureHelpCountIs(1);
verify.signatureHelpArgumentCountIs(4);

verify.currentSignatureParameterCountIs(4);
verify.currentSignatureHelpIs('f(templateStrings: any, x: any, y: any, z: any): number');
verify.currentParameterHelpArgumentNameIs("templateStrings");
verify.currentParameterSpanIs("templateStrings: any");
});
18 changes: 18 additions & 0 deletions tests/cases/fourslash/signatureHelpTaggedTemplates3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />

//// function f(templateStrings, x, y, z) { return 10; }
//// function g(templateStrings, x, y, z) { return ""; }
////
//// f ` qwerty ${/*1*/ /*2*/123/*3*/ /*4*/} asdf ${ 41234 } zxcvb ${ g ` ` } `

test.markers().forEach(m => {
goTo.position(m.position);

verify.signatureHelpCountIs(1);
verify.signatureHelpArgumentCountIs(4);

verify.currentSignatureParameterCountIs(4);
verify.currentSignatureHelpIs('f(templateStrings: any, x: any, y: any, z: any): number');
verify.currentParameterHelpArgumentNameIs("x");
verify.currentParameterSpanIs("x: any");
});
18 changes: 18 additions & 0 deletions tests/cases/fourslash/signatureHelpTaggedTemplates4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />

//// function f(templateStrings, x, y, z) { return 10; }
//// function g(templateStrings, x, y, z) { return ""; }
////
//// f ` qwerty ${ 123 } asdf ${/*1*/ /*2*/ /*3*/41/*4*/234/*5*/ /*6*/} zxcvb ${ g ` ` } `

test.markers().forEach(m => {
goTo.position(m.position);

verify.signatureHelpCountIs(1);
verify.signatureHelpArgumentCountIs(4);

verify.currentSignatureParameterCountIs(4);
verify.currentSignatureHelpIs('f(templateStrings: any, x: any, y: any, z: any): number');
verify.currentParameterHelpArgumentNameIs("y");
verify.currentParameterSpanIs("y: any");
});
18 changes: 18 additions & 0 deletions tests/cases/fourslash/signatureHelpTaggedTemplates5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />

//// function f(templateStrings, x, y, z) { return 10; }
//// function g(templateStrings, x, y, z) { return ""; }
////
//// f ` qwerty ${ 123 } asdf ${ 41234 } zxcvb ${/*1*/ /*2*/g/*3*/ /*4*/` `/*5*/ /*6*/} `

test.markers().forEach(m => {
goTo.position(m.position);

verify.signatureHelpCountIs(1);
verify.signatureHelpArgumentCountIs(4);

verify.currentSignatureParameterCountIs(4);
verify.currentSignatureHelpIs('f(templateStrings: any, x: any, y: any, z: any): number');
verify.currentParameterHelpArgumentNameIs("z");
verify.currentParameterSpanIs("z: any");
});
18 changes: 18 additions & 0 deletions tests/cases/fourslash/signatureHelpTaggedTemplates6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />

//// function f(templateStrings, x, y, z) { return 10; }
//// function g(templateStrings, x, y, z) { return ""; }
////
//// f ` qwerty ${ 123 } asdf ${ 41234 } zxcvb ${ g `/*1*/ /*2*/ /*3*/` } `

test.markers().forEach(m => {
goTo.position(m.position);

verify.signatureHelpCountIs(1);
verify.signatureHelpArgumentCountIs(1);

verify.currentSignatureParameterCountIs(4);
verify.currentSignatureHelpIs('g(templateStrings: any, x: any, y: any, z: any): string');
verify.currentParameterHelpArgumentNameIs("templateStrings");
verify.currentParameterSpanIs("templateStrings: any");
});
Loading