Skip to content

Commit 05eac42

Browse files
author
Andy Hanson
committed
Improve isPossiblyTypeArgumentPosition
1 parent 3bab6af commit 05eac42

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed

src/services/completions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ namespace ts.Completions {
10561056
const isImportType = isLiteralImportTypeNode(node);
10571057
const isTypeLocation = insideJsDocTagTypeExpression || (isImportType && !(node as ImportTypeNode).isTypeOf) || isPartOfTypeNode(node.parent);
10581058
const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration(node);
1059-
const allowTypeOrValue = isRhsOfImportDeclaration || (!isTypeLocation && isPossiblyTypeArgumentPosition(contextToken, sourceFile));
1059+
const allowTypeOrValue = isRhsOfImportDeclaration || (!isTypeLocation && isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker));
10601060
if (isEntityName(node) || isImportType) {
10611061
let symbol = typeChecker.getSymbolAtLocation(node);
10621062
if (symbol) {
@@ -1265,7 +1265,7 @@ namespace ts.Completions {
12651265

12661266
function filterGlobalCompletion(symbols: Symbol[]): void {
12671267
const isTypeOnlyCompletion = insideJsDocTagTypeExpression || !isContextTokenValueLocation(contextToken) && (isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken));
1268-
const allowTypes = isTypeOnlyCompletion || !isContextTokenValueLocation(contextToken) && isPossiblyTypeArgumentPosition(contextToken, sourceFile);
1268+
const allowTypes = isTypeOnlyCompletion || !isContextTokenValueLocation(contextToken) && isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker);
12691269
if (isTypeOnlyCompletion) keywordFilters = KeywordCompletionFilters.TypeKeywords;
12701270

12711271
filterMutate(symbols, symbol => {

src/services/signatureHelp.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ namespace ts.SignatureHelp {
5858
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
5959
}
6060
else {
61-
const type = checker.getTypeAtLocation(invocation.called)!; // TODO: GH#18217
62-
const signatures = isNewExpression(invocation.called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
63-
const candidates = signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= argumentInfo.argumentCount);
61+
const candidates = getPossibleGenericSignatures(invocation.called, argumentInfo.argumentCount, checker);
6462
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
6563
}
6664
}
@@ -205,7 +203,7 @@ namespace ts.SignatureHelp {
205203
};
206204
}
207205
else {
208-
const typeArgInfo = isPossiblyTypeArgumentPosition(node, sourceFile);
206+
const typeArgInfo = getPossibleTypeArgumentsInfo(node, sourceFile);
209207
if (typeArgInfo) {
210208
const { called, nTypeArguments } = typeArgInfo;
211209
const invocation: Invocation = { kind: InvocationKind.TypeArgs, called };

src/services/utilities.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,11 +924,23 @@ namespace ts {
924924
}
925925
}
926926

927+
export function isPossiblyTypeArgumentPosition(token: Node, sourceFile: SourceFile, checker: TypeChecker): boolean {
928+
const info = getPossibleTypeArgumentsInfo(token, sourceFile);
929+
return info !== undefined && getPossibleGenericSignatures(info.called, info.nTypeArguments, checker).length !== 0;
930+
}
931+
932+
export function getPossibleGenericSignatures(called: Expression, typeArgumentCount: number, checker: TypeChecker): ReadonlyArray<Signature> {
933+
const type = checker.getTypeAtLocation(called)!; // TODO: GH#18217
934+
const signatures = isNewExpression(called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
935+
return signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount);
936+
}
937+
927938
export interface PossibleTypeArgumentInfo {
928939
readonly called: Identifier;
929940
readonly nTypeArguments: number;
930941
}
931-
export function isPossiblyTypeArgumentPosition(tokenIn: Node, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
942+
// Get info for an expression like `f <` that may be the start of type arguments.
943+
export function getPossibleTypeArgumentsInfo(tokenIn: Node, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined {
932944
let token: Node | undefined = tokenIn;
933945
// This function determines if the node could be type argument position
934946
// Since during editing, when type argument list is not complete,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////const x = 0;
4+
////type T = number;
5+
////function f(x: number) {}
6+
////function g<T>(x: T) {}
7+
8+
////x + /*0*/
9+
////x < /*1*/
10+
////f < /*2*/
11+
////g < /*3*/
12+
13+
verify.completions(
14+
{ marker: ["0", "1", "2"], includes: "x", excludes: "T" },
15+
{ marker: "3", includes: ["x", "T"] },
16+
);

0 commit comments

Comments
 (0)