Skip to content

Commit 49ae281

Browse files
committed
Start testing signature counts and adjust some syntactic computations
1 parent 8a765d7 commit 49ae281

File tree

4 files changed

+104
-109
lines changed

4 files changed

+104
-109
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4435,7 +4435,11 @@ module ts {
44354435
// must fill it up with the appropriate candidate signatures
44364436
function getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature {
44374437
var links = getNodeLinks(node);
4438-
if (!links.resolvedSignature) {
4438+
// If getResolvedSignature has already been called, we will have cached the resolvedSignature.
4439+
// However, it is possible that either candidatesOutArray was not passed in the first time,
4440+
// or that a different candidatesOutArray was passed in. Therefore, we need to redo the work
4441+
// to correctly fill the candidatesOutArray.
4442+
if (!links.resolvedSignature || candidatesOutArray) {
44394443
links.resolvedSignature = anySignature;
44404444
links.resolvedSignature = node.kind === SyntaxKind.CallExpression
44414445
? resolveCallExpression(node, candidatesOutArray)

src/services/services.ts

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ module ts {
9696
public flags: NodeFlags;
9797
public parent: Node;
9898
private _children: Node[];
99-
private _syntheticParent: Node;
10099

101100
public getSourceFile(): SourceFile {
102101
var node: Node = this;
@@ -152,9 +151,6 @@ module ts {
152151
if (pos < node.pos) {
153152
pos = this.addSyntheticNodes(list._children, pos, node.pos);
154153
}
155-
else {
156-
(<NodeObject>node)._syntheticParent = list;
157-
}
158154
list._children.push(node);
159155
pos = node.end;
160156
}
@@ -207,11 +203,6 @@ module ts {
207203
return this._children;
208204
}
209205

210-
public getIndexOfChild(child: Node): number {
211-
if (!this._children) this.createChildren();
212-
return this._children.indexOf(child);
213-
}
214-
215206
public getFirstToken(sourceFile?: SourceFile): Node {
216207
var children = this.getChildren();
217208
for (var i = 0; i < children.length; i++) {
@@ -229,10 +220,6 @@ module ts {
229220
if (child.kind > SyntaxKind.Missing) return child.getLastToken(sourceFile);
230221
}
231222
}
232-
233-
public getSyntheticParentOrParent(): Node {
234-
return this._syntheticParent || this.parent;
235-
}
236223
}
237224

238225
class SymbolObject implements Symbol {
@@ -3496,26 +3483,43 @@ module ts {
34963483
// If node is an argument, returns its index in the argument list
34973484
// If not, returns -1
34983485
function getArgumentIndex(node: Node): number {
3499-
// Treat the open paren / angle bracket of a call as the introduction of parameter slot 0
3500-
var parent = (<NodeObject>node).getSyntheticParentOrParent();
3501-
if (parent.kind === SyntaxKind.SyntaxList) {
3502-
var grandparent = parent.parent;
3503-
if (grandparent.kind === SyntaxKind.CallExpression || grandparent.kind === SyntaxKind.NewExpression) {
3504-
var index = (<NodeObject>parent).getIndexOfChild(node);
3505-
Debug.assert(index >= 0);
3506-
return index;
3507-
}
3486+
if (node.parent.kind !== SyntaxKind.CallExpression && node.parent.kind !== SyntaxKind.NewExpression) {
3487+
return -1;
35083488
}
35093489

3490+
var parent = <CallExpression>node.parent;
3491+
// Find out if 'node' is an argument, a type argument, or neither
3492+
// Treat the open paren / angle bracket of a call as the introduction of parameter slot 0
35103493
if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) {
3511-
return parent.kind === SyntaxKind.CallExpression || parent.kind === SyntaxKind.NewExpression
3512-
? 0
3513-
: -1;
3494+
return 0;
35143495
}
3496+
3497+
var argumentListOrTypeArgumentList: NodeArray<Node>;
3498+
if (parent.typeArguments && node.pos >= parent.typeArguments.pos && node.end <= parent.typeArguments.end) {
3499+
argumentListOrTypeArgumentList = parent.typeArguments;
3500+
}
3501+
else if (parent.arguments && node.pos >= parent.arguments.pos && node.end <= parent.arguments.end) {
3502+
argumentListOrTypeArgumentList = parent.arguments;
3503+
}
3504+
3505+
return argumentListOrTypeArgumentList ? argumentListOrTypeArgumentList.indexOf(node) : -1;
3506+
3507+
// if (parent.kind === SyntaxKind.SyntaxList) {
3508+
// var grandparent = parent.parent;
3509+
// if (grandparent.kind === SyntaxKind.CallExpression || grandparent.kind === SyntaxKind.NewExpression) {
3510+
// var index = (<NodeObject>parent).getIndexOfChild(node);
3511+
// Debug.assert(index >= 0);
3512+
// return index;
3513+
// }
3514+
// }
3515+
3516+
// if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) {
3517+
// return parent.kind === SyntaxKind.CallExpression || parent.kind === SyntaxKind.NewExpression
3518+
// ? 0
3519+
// : -1;
3520+
// }
35153521

35163522
// TODO: Handle close paren or close angle bracket on nonempty list
3517-
3518-
return -1;
35193523
}
35203524

35213525
function getSignatureHelpArgumentContext(node: Node): {
@@ -3529,7 +3533,7 @@ module ts {
35293533
if (!isToken || position <= node.getStart() || position >= node.getEnd()) {
35303534
// This is a temporary hack until we figure out our token story.
35313535
// The correct solution is to get the previous token
3532-
node = SignatureInfoHelpers.findClosestRightmostSiblingFromLeft(position, sourceFile);
3536+
node = SignatureInfoHelpers.findPrecedingToken(position, sourceFile);
35333537

35343538
if (!node) {
35353539
return undefined;
@@ -3559,9 +3563,8 @@ module ts {
35593563

35603564
// TODO: Handle previous token logic
35613565
// TODO: Handle generic call with incomplete
3562-
3563-
return undefined;
35643566
}
3567+
return undefined;
35653568
}
35663569

35673570
synchronizeHostData();
@@ -3578,7 +3581,7 @@ module ts {
35783581
var candidates = <Signature[]>[];
35793582
var resolvedSignature = typeInfoResolver.getResolvedSignature(call, candidates);
35803583
return candidates.length
3581-
? new SignatureHelpItems(undefined, undefined, undefined)
3584+
? new SignatureHelpItems(new Array<SignatureHelpItem>(candidates.length), undefined, undefined)
35823585
: undefined;
35833586
}
35843587

src/services/signatureInfoHelpers.ts

Lines changed: 64 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -345,82 +345,70 @@ module ts {
345345
// return null;
346346
//}
347347

348-
export function findClosestRightmostSiblingFromLeft(position: number, sourceFile: SourceFile): Node {
349-
return search(sourceFile);
350-
351-
function search(n: Node): Node {
352-
353-
var childCandidate: Node;
354-
forEachChild(n, c => {
355-
if (c.kind === SyntaxKind.OmittedExpression || c.kind === SyntaxKind.Missing) {
356-
return;
357-
}
358-
if (c.end <= position || c.getStart() < position) {
359-
childCandidate = c;
360-
}
361-
return c.end > position;
362-
});
363-
364-
if (childCandidate) {
365-
if (childCandidate.end > position || !isCompletedNode(childCandidate, position, sourceFile)) {
366-
return search(childCandidate) || childCandidate;
367-
}
368-
else {
369-
return childCandidate;
370-
}
371-
}
372-
}
348+
export function findPrecedingToken(position: number, sourceFile: SourceFile): Node {
349+
return find(sourceFile, /*diveIntoLastChild*/ false);
350+
351+
function find(n: Node, diveIntoLastChild: boolean): Node {
352+
if (isToken(n)) {
353+
return n;
354+
}
355+
356+
var children = n.getChildren();
357+
if (diveIntoLastChild) {
358+
var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ children.length);
359+
return candidate && find(candidate, /*diveIntoLastChild*/ true);
360+
}
361+
362+
for (var i = 0, len = children.length; i < len; ++i) {
363+
var child = children[i];
364+
if (nodeHasTokens(child)) {
365+
if (position < child.end) {
366+
if (child.getStart() >= position) {
367+
// actual start of the node is past the position - previous token should be at the end of previous child
368+
var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ i);
369+
return candidate && find(candidate, /*diveIntoLastChild*/ true)
370+
}
371+
else {
372+
// candidate should be in this node
373+
return find(child, diveIntoLastChild);
374+
}
375+
}
376+
}
377+
}
378+
379+
// here we know that none of child token nodes embrace the position
380+
// try to find the closest token on the left
381+
if (children.length) {
382+
var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ children.length);
383+
return candidate && find(candidate, /*diveIntoLastChild*/ true);
384+
}
385+
}
386+
387+
/// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition'
388+
function findLastChildNodeCandidate(children: Node[], exclusiveStartPosition: number): Node {
389+
for (var i = exclusiveStartPosition - 1; i >= 0; --i) {
390+
if (nodeHasTokens(children[i])) {
391+
return children[i];
392+
}
393+
}
394+
}
395+
396+
function isToken(n: Node): boolean {
397+
return n.kind < SyntaxKind.Missing;
398+
}
399+
400+
function nodeHasTokens(n: Node): boolean {
401+
if (n.kind === SyntaxKind.ExpressionStatement) {
402+
return nodeHasTokens((<ExpressionStatement>n).expression);
403+
}
404+
405+
if (n.kind === SyntaxKind.EndOfFileToken || n.kind === SyntaxKind.OmittedExpression || n.kind === SyntaxKind.Missing) {
406+
return false;
407+
}
408+
409+
// SyntaxList is already realized so getChildCount should be fast and non-expensive
410+
return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0;
411+
}
373412
}
374-
375-
function isCompletedNode(n: Node, position: number, sourceFile: SourceFile): boolean {
376-
switch (n.kind) {
377-
case SyntaxKind.ClassDeclaration:
378-
case SyntaxKind.InterfaceDeclaration:
379-
case SyntaxKind.EnumDeclaration:
380-
case SyntaxKind.ObjectLiteral:
381-
case SyntaxKind.Block:
382-
case SyntaxKind.CatchBlock:
383-
case SyntaxKind.FinallyBlock:
384-
case SyntaxKind.FunctionBlock:
385-
case SyntaxKind.ModuleBlock:
386-
return isNodeEndWith(n, sourceFile, CharacterCodes.closeBrace);
387-
case SyntaxKind.ParenExpression:
388-
case SyntaxKind.CallSignature:
389-
case SyntaxKind.CallExpression:
390-
return isNodeEndWith(n, sourceFile, CharacterCodes.closeParen);
391-
case SyntaxKind.FunctionDeclaration:
392-
case SyntaxKind.FunctionExpression:
393-
case SyntaxKind.Method:
394-
case SyntaxKind.ArrowFunction:
395-
return !(<FunctionDeclaration>n).body || isCompletedNode((<FunctionDeclaration>n).body, position, sourceFile);
396-
case SyntaxKind.ModuleDeclaration:
397-
return (<ModuleDeclaration>n).body && isCompletedNode((<ModuleDeclaration>n).body, position, sourceFile);
398-
case SyntaxKind.IfStatement:
399-
if ((<IfStatement>n).thenStatement && (<IfStatement>n).thenStatement.end > position) {
400-
return isCompletedNode((<IfStatement>n).thenStatement, position, sourceFile);
401-
}
402-
else if ((<IfStatement>n).elseStatement) {
403-
return isCompletedNode((<IfStatement>n).elseStatement, position, sourceFile);
404-
}
405-
else {
406-
return true;
407-
}
408-
break;
409-
case SyntaxKind.ExpressionStatement:
410-
return isCompletedNode((<ExpressionStatement>n).expression, position, sourceFile);
411-
case SyntaxKind.ArrayLiteral:
412-
return isNodeEndWith(n, sourceFile, CharacterCodes.closeBracket);
413-
case SyntaxKind.Missing:
414-
return false;
415-
default:
416-
return true;
417-
}
418-
}
419-
420-
function isNodeEndWith(n: Node, sourceFile: SourceFile, charCode: CharacterCodes): boolean {
421-
var pos = n.end - 1; // Node.end is exclusive
422-
return pos < sourceFile.text.length && sourceFile.text.charCodeAt(pos) === charCode;
423-
}
424-
425413
}
426414
}

tests/cases/fourslash/fourslash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ module FourSlashInterface {
291291
}
292292

293293
public signatureHelpCountIs(expected: number) {
294-
// FourSlash.currentTestState.verifySignatureHelpCount(expected);
294+
FourSlash.currentTestState.verifySignatureHelpCount(expected);
295295
}
296296

297297
public currentSignatureParamterCountIs(expected: number) {

0 commit comments

Comments
 (0)