Only provide signature help contextually on a character trigger.

This commit is contained in:
Daniel Rosenwasser
2018-07-03 17:04:03 -07:00
parent a3b2237437
commit 9481faab98

View File

@@ -29,8 +29,11 @@ namespace ts.SignatureHelp {
return undefined;
}
if (shouldCarefullyCheckContext(triggerReason)) {
// In the middle of a string, don't provide signature help unless the user explicitly requested it.
// Only need to be careful if the user typed a character and signature help wasn't showing.
const shouldCarefullyCheckContext = !!triggerReason && triggerReason.kind === "characterTyped";
// Bail out quickly in the middle of a string or comment, don't provide signature help unless the user explicitly requested it.
if (shouldCarefullyCheckContext) {
if (isInString(sourceFile, position, startingToken) || isInComment(sourceFile, position)) {
return undefined;
}
@@ -41,8 +44,8 @@ namespace ts.SignatureHelp {
cancellationToken.throwIfCancellationRequested();
// Semantic filtering of signature help
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker);
// Extra syntactic and semantic filtering of signature help
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker, sourceFile, startingToken, shouldCarefullyCheckContext);
cancellationToken.throwIfCancellationRequested();
if (!candidateInfo) {
@@ -57,24 +60,57 @@ namespace ts.SignatureHelp {
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
}
function shouldCarefullyCheckContext(reason: SignatureHelpTriggerReason | undefined) {
// Only need to be careful if the user typed a character and signature help wasn't showing.
return !!reason && reason.kind === "characterTyped";
}
function getCandidateInfo(
argumentInfo: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean):
{ readonly candidates: ReadonlyArray<Signature>, readonly resolvedSignature: Signature } | undefined {
function getCandidateInfo(argumentInfo: ArgumentListInfo, checker: TypeChecker): { readonly candidates: ReadonlyArray<Signature>, readonly resolvedSignature: Signature } | undefined {
const { invocation } = argumentInfo;
if (invocation.kind === InvocationKind.Call) {
if (onlyUseSyntacticOwners) {
if (isCallOrNewExpression(invocation.node)) {
const invocationChildren = invocation.node.getChildren(sourceFile);
switch (startingToken.kind) {
case SyntaxKind.OpenParenToken:
if (!contains(invocationChildren, startingToken)) {
return undefined;
}
break;
case SyntaxKind.CommaToken:
const containingList = findContainingList(startingToken);
if (!containingList || !contains(invocationChildren, findContainingList(startingToken))) {
return undefined;
}
break;
case SyntaxKind.LessThanToken:
if (!lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.node.expression)) {
return undefined;
}
break;
default:
return undefined;
}
}
else {
return undefined;
}
}
const candidates: Signature[] = [];
const resolvedSignature = checker.getResolvedSignature(invocation.node, candidates, argumentInfo.argumentCount)!; // TODO: GH#18217
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
}
else {
else if (invocation.kind === InvocationKind.TypeArgs) {
if (onlyUseSyntacticOwners && !lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.called)) {
return undefined;
}
const type = checker.getTypeAtLocation(invocation.called)!; // TODO: GH#18217
const signatures = isNewExpression(invocation.called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
const candidates = signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= argumentInfo.argumentCount);
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
}
else {
Debug.assertNever(invocation);
}
}
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
@@ -107,6 +143,14 @@ namespace ts.SignatureHelp {
}
}
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
const precedingToken = Debug.assertDefined(
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
);
return rangeContainsRange(calledExpression, precedingToken);
}
export interface ArgumentInfoForCompletions {
readonly invocation: CallLikeExpression;
readonly argumentIndex: number;