mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Only provide signature help contextually on a character trigger.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user