Skip to content

Commit 5971b68

Browse files
authored
fix(45224): show inlay hints for setter parameter (#45229)
1 parent c408043 commit 5971b68

File tree

7 files changed

+95
-40
lines changed

7 files changed

+95
-40
lines changed

src/compiler/checker.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16442,25 +16442,6 @@ namespace ts {
1644216442
(hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node));
1644316443
}
1644416444

16445-
function hasContextSensitiveParameters(node: FunctionLikeDeclaration) {
16446-
// Functions with type parameters are not context sensitive.
16447-
if (!node.typeParameters) {
16448-
// Functions with any parameters that lack type annotations are context sensitive.
16449-
if (some(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) {
16450-
return true;
16451-
}
16452-
if (node.kind !== SyntaxKind.ArrowFunction) {
16453-
// If the first parameter is not an explicit 'this' parameter, then the function has
16454-
// an implicit 'this' parameter which is subject to contextual typing.
16455-
const parameter = firstOrUndefined(node.parameters);
16456-
if (!(parameter && parameterIsThisKeyword(parameter))) {
16457-
return true;
16458-
}
16459-
}
16460-
}
16461-
return false;
16462-
}
16463-
1646416445
function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) {
1646516446
// TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value.
1646616447
return !node.typeParameters && !getEffectiveReturnTypeNode(node) && !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body);

src/compiler/utilities.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7343,4 +7343,23 @@ namespace ts {
73437343
return (parent as SourceFile).statements;
73447344
}
73457345
}
7346+
7347+
export function hasContextSensitiveParameters(node: FunctionLikeDeclaration) {
7348+
// Functions with type parameters are not context sensitive.
7349+
if (!node.typeParameters) {
7350+
// Functions with any parameters that lack type annotations are context sensitive.
7351+
if (some(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) {
7352+
return true;
7353+
}
7354+
if (node.kind !== SyntaxKind.ArrowFunction) {
7355+
// If the first parameter is not an explicit 'this' parameter, then the function has
7356+
// an implicit 'this' parameter which is subject to contextual typing.
7357+
const parameter = firstOrUndefined(node.parameters);
7358+
if (!(parameter && parameterIsThisKeyword(parameter))) {
7359+
return true;
7360+
}
7361+
}
7362+
}
7363+
return false;
7364+
}
73467365
}

src/services/inlayHints.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ namespace ts.InlayHints {
6464
visitCallOrNewExpression(node);
6565
}
6666
else {
67-
if (preferences.includeInlayFunctionParameterTypeHints && isFunctionExpressionLike(node)) {
68-
visitFunctionExpressionLikeForParameterType(node);
67+
if (preferences.includeInlayFunctionParameterTypeHints && isFunctionLikeDeclaration(node) && hasContextSensitiveParameters(node)) {
68+
visitFunctionLikeForParameterType(node);
6969
}
7070
if (preferences.includeInlayFunctionLikeReturnTypeHints && isSignatureSupportingReturnAnnotation(node)) {
7171
visitFunctionDeclarationLikeForReturnType(node);
@@ -78,10 +78,6 @@ namespace ts.InlayHints {
7878
return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) || isMethodDeclaration(node) || isGetAccessorDeclaration(node);
7979
}
8080

81-
function isFunctionExpressionLike(node: Node): node is ArrowFunction | FunctionExpression {
82-
return isArrowFunction(node) || isFunctionExpression(node);
83-
}
84-
8581
function addParameterHints(text: string, position: number, isFirstVariadicArgument: boolean) {
8682
result.push({
8783
text: `${isFirstVariadicArgument ? "..." : ""}${truncation(text, maxHintsLength)}:`,
@@ -207,7 +203,7 @@ namespace ts.InlayHints {
207203
}
208204

209205
function isHintableExpression(node: Node) {
210-
return isLiteralExpression(node) || isBooleanLiteral(node) || isFunctionExpressionLike(node) || isObjectLiteralExpression(node) || isArrayLiteralExpression(node);
206+
return isLiteralExpression(node) || isBooleanLiteral(node) || isArrowFunction(node) || isFunctionExpression(node) || isObjectLiteralExpression(node) || isArrayLiteralExpression(node);
211207
}
212208

213209
function visitFunctionDeclarationLikeForReturnType(decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration) {
@@ -248,24 +244,14 @@ namespace ts.InlayHints {
248244
return decl.parameters.end;
249245
}
250246

251-
function visitFunctionExpressionLikeForParameterType(expr: ArrowFunction | FunctionExpression) {
252-
if (!expr.parameters.length || expr.parameters.every(param => !!getEffectiveTypeAnnotationNode(param))) {
253-
return;
254-
}
255-
256-
const contextualType = checker.getContextualType(expr);
257-
if (!contextualType) {
258-
return;
259-
}
260-
261-
const signatures = checker.getSignaturesOfType(contextualType, SignatureKind.Call);
262-
const signature = firstOrUndefined(signatures);
247+
function visitFunctionLikeForParameterType(node: FunctionLikeDeclaration) {
248+
const signature = checker.getSignatureFromDeclaration(node);
263249
if (!signature) {
264250
return;
265251
}
266252

267-
for (let i = 0; i < expr.parameters.length && i < signature.parameters.length; ++i) {
268-
const param = expr.parameters[i];
253+
for (let i = 0; i < node.parameters.length && i < signature.parameters.length; ++i) {
254+
const param = node.parameters[i];
269255
const effectiveTypeAnnotation = getEffectiveTypeAnnotationNode(param);
270256

271257
if (effectiveTypeAnnotation) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////class Foo {
4+
//// #value = 0;
5+
//// get foo(): number { return this.#value; }
6+
//// set foo(value/**/) { this.#value = value; }
7+
////}
8+
9+
const [marker] = test.markers();
10+
verify.getInlayHints([
11+
{
12+
text: ': number',
13+
position: marker.position,
14+
kind: ts.InlayHintKind.Type,
15+
whitespaceBefore: true
16+
}
17+
], undefined, {
18+
includeInlayFunctionParameterTypeHints: true
19+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////class Foo {
4+
//// #value = 0;
5+
//// get foo(): number { return this.#value; }
6+
//// set foo(value/**/: number) { this.#value = value; }
7+
////}
8+
9+
verify.getInlayHints([], undefined, {
10+
includeInlayFunctionParameterTypeHints: true
11+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @allowJs: true
4+
// @checkJs: true
5+
// @Filename: /a.js
6+
////class Foo {
7+
//// #value = 0;
8+
//// get foo() { return this.#value; }
9+
//// /**
10+
//// * @param {number} value
11+
//// */
12+
//// set foo(value/**/) { this.#value = value; }
13+
////}
14+
15+
verify.getInlayHints([], undefined, {
16+
includeInlayFunctionParameterTypeHints: true
17+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @allowJs: true
4+
// @checkJs: true
5+
// @Filename: /a.js
6+
////class Foo {
7+
//// #value = 0;
8+
//// get foo() { return this.#value; }
9+
//// set foo(value/**/) { this.#value = value; }
10+
////}
11+
12+
const [marker] = test.markers();
13+
verify.getInlayHints([
14+
{
15+
text: ': number',
16+
position: marker.position,
17+
kind: ts.InlayHintKind.Type,
18+
whitespaceBefore: true
19+
}
20+
], undefined, {
21+
includeInlayFunctionParameterTypeHints: true
22+
});

0 commit comments

Comments
 (0)