From 7b0e66518df5457d8534458abe1c264a6d2b4dcf Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Mon, 16 Aug 2021 14:11:35 -0700 Subject: [PATCH] Cherry-pick PR #45426 into release-4.4 (#45445) Component commits: 01077c1299 fix(45417): show inlay hints for null and literal-like identifiers Co-authored-by: Oleksandr T --- src/compiler/checker.ts | 4 - src/compiler/utilities.ts | 5 + src/services/classifier2020.ts | 4 - src/services/inlayHints.ts | 15 ++- .../cases/fourslash/inlayHintsShouldWork64.ts | 94 +++++++++++++++++++ 5 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 tests/cases/fourslash/inlayHintsShouldWork64.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 179460eb1ee8e..c11a1eb592308 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26284,10 +26284,6 @@ namespace ts { return isTypeAssignableToKind(checkComputedPropertyName(name), TypeFlags.NumberLike); } - function isInfinityOrNaNString(name: string | __String): boolean { - return name === "Infinity" || name === "-Infinity" || name === "NaN"; - } - function isNumericLiteralName(name: string | __String) { // The intent of numeric names is that // - they are names with text in a numeric form, and that diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 705a87ea36cd1..00390b144b590 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7367,4 +7367,9 @@ namespace ts { } return false; } + + /* @internal */ + export function isInfinityOrNaNString(name: string | __String): boolean { + return name === "Infinity" || name === "-Infinity" || name === "NaN"; + } } diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index c890b3f6dbe4d..2d227e41162b5 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -225,10 +225,6 @@ namespace ts.classifier.v2020 { return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); } - function isInfinityOrNaNString(name: __String): boolean { - return name === "Infinity" || name === "NaN"; - } - const tokenFromDeclarationMapping = new Map([ [SyntaxKind.VariableDeclaration, TokenType.variable], [SyntaxKind.Parameter, TokenType.parameter], diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index ba278c5f30199..56930c169ae9b 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -204,15 +204,22 @@ namespace ts.InlayHints { function isHintableExpression(node: Node) { switch (node.kind) { - case SyntaxKind.PrefixUnaryExpression: - return isLiteralExpression((node as PrefixUnaryExpression).operand); + case SyntaxKind.PrefixUnaryExpression: { + const operand = (node as PrefixUnaryExpression).operand; + return isLiteralExpression(operand) || isIdentifier(operand) && isInfinityOrNaNString(operand.escapedText); + } case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: case SyntaxKind.ArrowFunction: case SyntaxKind.FunctionExpression: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.NullKeyword: return true; + case SyntaxKind.Identifier: { + const name = (node as Identifier).escapedText; + return isUndefined(name) || isInfinityOrNaNString(name); + } } return isLiteralExpression(node); } @@ -310,5 +317,9 @@ namespace ts.InlayHints { printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ file, writer); }); } + + function isUndefined(name: __String) { + return name === "undefined"; + } } } diff --git a/tests/cases/fourslash/inlayHintsShouldWork64.ts b/tests/cases/fourslash/inlayHintsShouldWork64.ts new file mode 100644 index 0000000000000..aa29da68a3ed3 --- /dev/null +++ b/tests/cases/fourslash/inlayHintsShouldWork64.ts @@ -0,0 +1,94 @@ +/// + +////function foo( +//// a: string, +//// b: undefined, +//// c: null, +//// d: boolean, +//// e: boolean, +//// f: number, +//// g: number, +//// h: number, +//// i: RegExp, +//// j: bigint, +////) { +////} +//// +////foo( +//// /*a*/"hello", +//// /*b*/undefined, +//// /*c*/null, +//// /*d*/true, +//// /*e*/false, +//// /*f*/Infinity, +//// /*g*/-Infinity, +//// /*h*/NaN, +//// /*i*//hello/g, +//// /*j*/123n, +////); + +const [a, b, c, d, e, f, g, h, i, j] = test.markers(); +verify.getInlayHints([ + { + text: "a:", + position: a.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "b:", + position: b.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "c:", + position: c.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "d:", + position: d.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "e:", + position: e.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "f:", + position: f.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "g:", + position: g.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "h:", + position: h.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "i:", + position: i.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + }, + { + text: "j:", + position: j.position, + kind: ts.InlayHintKind.Parameter, + whitespaceAfter: true + } +], undefined, { + includeInlayParameterNameHints: "literals" +});