Start testing signature counts and adjust some syntactic computations

This commit is contained in:
Jason Freeman 2014-09-15 17:03:08 -07:00
parent 8a765d7680
commit 49ae281059
4 changed files with 104 additions and 109 deletions

View File

@ -4435,7 +4435,11 @@ module ts {
// must fill it up with the appropriate candidate signatures
function getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature {
var links = getNodeLinks(node);
if (!links.resolvedSignature) {
// If getResolvedSignature has already been called, we will have cached the resolvedSignature.
// However, it is possible that either candidatesOutArray was not passed in the first time,
// or that a different candidatesOutArray was passed in. Therefore, we need to redo the work
// to correctly fill the candidatesOutArray.
if (!links.resolvedSignature || candidatesOutArray) {
links.resolvedSignature = anySignature;
links.resolvedSignature = node.kind === SyntaxKind.CallExpression
? resolveCallExpression(node, candidatesOutArray)

View File

@ -96,7 +96,6 @@ module ts {
public flags: NodeFlags;
public parent: Node;
private _children: Node[];
private _syntheticParent: Node;
public getSourceFile(): SourceFile {
var node: Node = this;
@ -152,9 +151,6 @@ module ts {
if (pos < node.pos) {
pos = this.addSyntheticNodes(list._children, pos, node.pos);
}
else {
(<NodeObject>node)._syntheticParent = list;
}
list._children.push(node);
pos = node.end;
}
@ -207,11 +203,6 @@ module ts {
return this._children;
}
public getIndexOfChild(child: Node): number {
if (!this._children) this.createChildren();
return this._children.indexOf(child);
}
public getFirstToken(sourceFile?: SourceFile): Node {
var children = this.getChildren();
for (var i = 0; i < children.length; i++) {
@ -229,10 +220,6 @@ module ts {
if (child.kind > SyntaxKind.Missing) return child.getLastToken(sourceFile);
}
}
public getSyntheticParentOrParent(): Node {
return this._syntheticParent || this.parent;
}
}
class SymbolObject implements Symbol {
@ -3496,26 +3483,43 @@ module ts {
// If node is an argument, returns its index in the argument list
// If not, returns -1
function getArgumentIndex(node: Node): number {
// Treat the open paren / angle bracket of a call as the introduction of parameter slot 0
var parent = (<NodeObject>node).getSyntheticParentOrParent();
if (parent.kind === SyntaxKind.SyntaxList) {
var grandparent = parent.parent;
if (grandparent.kind === SyntaxKind.CallExpression || grandparent.kind === SyntaxKind.NewExpression) {
var index = (<NodeObject>parent).getIndexOfChild(node);
Debug.assert(index >= 0);
return index;
}
if (node.parent.kind !== SyntaxKind.CallExpression && node.parent.kind !== SyntaxKind.NewExpression) {
return -1;
}
var parent = <CallExpression>node.parent;
// Find out if 'node' is an argument, a type argument, or neither
// Treat the open paren / angle bracket of a call as the introduction of parameter slot 0
if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) {
return parent.kind === SyntaxKind.CallExpression || parent.kind === SyntaxKind.NewExpression
? 0
: -1;
return 0;
}
var argumentListOrTypeArgumentList: NodeArray<Node>;
if (parent.typeArguments && node.pos >= parent.typeArguments.pos && node.end <= parent.typeArguments.end) {
argumentListOrTypeArgumentList = parent.typeArguments;
}
else if (parent.arguments && node.pos >= parent.arguments.pos && node.end <= parent.arguments.end) {
argumentListOrTypeArgumentList = parent.arguments;
}
return argumentListOrTypeArgumentList ? argumentListOrTypeArgumentList.indexOf(node) : -1;
// if (parent.kind === SyntaxKind.SyntaxList) {
// var grandparent = parent.parent;
// if (grandparent.kind === SyntaxKind.CallExpression || grandparent.kind === SyntaxKind.NewExpression) {
// var index = (<NodeObject>parent).getIndexOfChild(node);
// Debug.assert(index >= 0);
// return index;
// }
// }
// if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) {
// return parent.kind === SyntaxKind.CallExpression || parent.kind === SyntaxKind.NewExpression
// ? 0
// : -1;
// }
// TODO: Handle close paren or close angle bracket on nonempty list
return -1;
}
function getSignatureHelpArgumentContext(node: Node): {
@ -3529,7 +3533,7 @@ module ts {
if (!isToken || position <= node.getStart() || position >= node.getEnd()) {
// This is a temporary hack until we figure out our token story.
// The correct solution is to get the previous token
node = SignatureInfoHelpers.findClosestRightmostSiblingFromLeft(position, sourceFile);
node = SignatureInfoHelpers.findPrecedingToken(position, sourceFile);
if (!node) {
return undefined;
@ -3559,9 +3563,8 @@ module ts {
// TODO: Handle previous token logic
// TODO: Handle generic call with incomplete
return undefined;
}
return undefined;
}
synchronizeHostData();
@ -3578,7 +3581,7 @@ module ts {
var candidates = <Signature[]>[];
var resolvedSignature = typeInfoResolver.getResolvedSignature(call, candidates);
return candidates.length
? new SignatureHelpItems(undefined, undefined, undefined)
? new SignatureHelpItems(new Array<SignatureHelpItem>(candidates.length), undefined, undefined)
: undefined;
}

View File

@ -345,82 +345,70 @@ module ts {
// return null;
//}
export function findClosestRightmostSiblingFromLeft(position: number, sourceFile: SourceFile): Node {
return search(sourceFile);
function search(n: Node): Node {
var childCandidate: Node;
forEachChild(n, c => {
if (c.kind === SyntaxKind.OmittedExpression || c.kind === SyntaxKind.Missing) {
return;
}
if (c.end <= position || c.getStart() < position) {
childCandidate = c;
}
return c.end > position;
});
if (childCandidate) {
if (childCandidate.end > position || !isCompletedNode(childCandidate, position, sourceFile)) {
return search(childCandidate) || childCandidate;
}
else {
return childCandidate;
}
}
}
export function findPrecedingToken(position: number, sourceFile: SourceFile): Node {
return find(sourceFile, /*diveIntoLastChild*/ false);
function find(n: Node, diveIntoLastChild: boolean): Node {
if (isToken(n)) {
return n;
}
var children = n.getChildren();
if (diveIntoLastChild) {
var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ children.length);
return candidate && find(candidate, /*diveIntoLastChild*/ true);
}
for (var i = 0, len = children.length; i < len; ++i) {
var child = children[i];
if (nodeHasTokens(child)) {
if (position < child.end) {
if (child.getStart() >= position) {
// actual start of the node is past the position - previous token should be at the end of previous child
var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ i);
return candidate && find(candidate, /*diveIntoLastChild*/ true)
}
else {
// candidate should be in this node
return find(child, diveIntoLastChild);
}
}
}
}
// here we know that none of child token nodes embrace the position
// try to find the closest token on the left
if (children.length) {
var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ children.length);
return candidate && find(candidate, /*diveIntoLastChild*/ true);
}
}
/// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition'
function findLastChildNodeCandidate(children: Node[], exclusiveStartPosition: number): Node {
for (var i = exclusiveStartPosition - 1; i >= 0; --i) {
if (nodeHasTokens(children[i])) {
return children[i];
}
}
}
function isToken(n: Node): boolean {
return n.kind < SyntaxKind.Missing;
}
function nodeHasTokens(n: Node): boolean {
if (n.kind === SyntaxKind.ExpressionStatement) {
return nodeHasTokens((<ExpressionStatement>n).expression);
}
if (n.kind === SyntaxKind.EndOfFileToken || n.kind === SyntaxKind.OmittedExpression || n.kind === SyntaxKind.Missing) {
return false;
}
// SyntaxList is already realized so getChildCount should be fast and non-expensive
return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0;
}
}
function isCompletedNode(n: Node, position: number, sourceFile: SourceFile): boolean {
switch (n.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ObjectLiteral:
case SyntaxKind.Block:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.FunctionBlock:
case SyntaxKind.ModuleBlock:
return isNodeEndWith(n, sourceFile, CharacterCodes.closeBrace);
case SyntaxKind.ParenExpression:
case SyntaxKind.CallSignature:
case SyntaxKind.CallExpression:
return isNodeEndWith(n, sourceFile, CharacterCodes.closeParen);
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.Method:
case SyntaxKind.ArrowFunction:
return !(<FunctionDeclaration>n).body || isCompletedNode((<FunctionDeclaration>n).body, position, sourceFile);
case SyntaxKind.ModuleDeclaration:
return (<ModuleDeclaration>n).body && isCompletedNode((<ModuleDeclaration>n).body, position, sourceFile);
case SyntaxKind.IfStatement:
if ((<IfStatement>n).thenStatement && (<IfStatement>n).thenStatement.end > position) {
return isCompletedNode((<IfStatement>n).thenStatement, position, sourceFile);
}
else if ((<IfStatement>n).elseStatement) {
return isCompletedNode((<IfStatement>n).elseStatement, position, sourceFile);
}
else {
return true;
}
break;
case SyntaxKind.ExpressionStatement:
return isCompletedNode((<ExpressionStatement>n).expression, position, sourceFile);
case SyntaxKind.ArrayLiteral:
return isNodeEndWith(n, sourceFile, CharacterCodes.closeBracket);
case SyntaxKind.Missing:
return false;
default:
return true;
}
}
function isNodeEndWith(n: Node, sourceFile: SourceFile, charCode: CharacterCodes): boolean {
var pos = n.end - 1; // Node.end is exclusive
return pos < sourceFile.text.length && sourceFile.text.charCodeAt(pos) === charCode;
}
}
}

View File

@ -291,7 +291,7 @@ module FourSlashInterface {
}
public signatureHelpCountIs(expected: number) {
// FourSlash.currentTestState.verifySignatureHelpCount(expected);
FourSlash.currentTestState.verifySignatureHelpCount(expected);
}
public currentSignatureParamterCountIs(expected: number) {