From da5f0fe9d4f273d0fb67039c67c7edc3a69ea3a9 Mon Sep 17 00:00:00 2001 From: hborchardt <66408901+hborchardt@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:49:38 +0100 Subject: [PATCH] Add missing members to array of objects in quickfix (#57143) --- src/services/codefixes/fixAddMissingMember.ts | 20 ++++++++++++++---- .../codeFixAddMissingProperties30.ts | 21 +++++++++++++++++++ .../codeFixAddMissingProperties31.ts | 21 +++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 tests/cases/fourslash/codeFixAddMissingProperties30.ts create mode 100644 tests/cases/fourslash/codeFixAddMissingProperties31.ts diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 9ef55283fd6..1210275178f 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -187,7 +187,7 @@ registerCodeFix({ return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => { eachDiagnostic(context, errorCodes, diag => { const info = getInfo(diag.file, diag.start, diag.code, checker, context.program); - if (!info || !addToSeen(seen, getNodeId(info.parentDeclaration) + "#" + info.token.text)) { + if (!info || !addToSeen(seen, getNodeId(info.parentDeclaration) + "#" + (info.kind === InfoKind.ObjectLiteral ? info.identifier : info.token.text))) { return; } if (fixId === fixMissingFunctionDeclaration && (info.kind === InfoKind.Function || info.kind === InfoKind.Signature)) { @@ -273,7 +273,8 @@ interface FunctionInfo { interface ObjectLiteralInfo { readonly kind: InfoKind.ObjectLiteral; - readonly token: Identifier; + readonly token: Node; + readonly identifier: string; readonly properties: Symbol[]; readonly parentDeclaration: ObjectLiteralExpression; readonly indentation?: number; @@ -315,7 +316,18 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), checker.getParameterType(signature, argIndex), /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false)); if (!length(properties)) return undefined; - return { kind: InfoKind.ObjectLiteral, token: param.name, properties, parentDeclaration: parent }; + return { kind: InfoKind.ObjectLiteral, token: param.name, identifier: param.name.text, properties, parentDeclaration: parent }; + } + + if (token.kind === SyntaxKind.OpenBraceToken && isObjectLiteralExpression(parent)) { + const targetType = checker.getContextualType(parent) || checker.getTypeAtLocation(parent); + const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), targetType, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false)); + if (!length(properties)) return undefined; + + // no identifier needed because the whole parentDeclaration has the error + const identifier = ""; + + return { kind: InfoKind.ObjectLiteral, token: parent, identifier, properties, parentDeclaration: parent }; } if (!isMemberName(token)) return undefined; @@ -325,7 +337,7 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent.initializer), targetType, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false)); if (!length(properties)) return undefined; - return { kind: InfoKind.ObjectLiteral, token, properties, parentDeclaration: parent.initializer }; + return { kind: InfoKind.ObjectLiteral, token, identifier: token.text, properties, parentDeclaration: parent.initializer }; } if (isIdentifier(token) && isJsxOpeningLikeElement(token.parent)) { diff --git a/tests/cases/fourslash/codeFixAddMissingProperties30.ts b/tests/cases/fourslash/codeFixAddMissingProperties30.ts new file mode 100644 index 00000000000..3475c38db76 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingProperties30.ts @@ -0,0 +1,21 @@ +/// + +////interface A { +//// a: number; +//// b: string; +////} +////function f(_obj: A[]): string { +//// return ""; +////} +////[|f([{}])|] + +debugger; +verify.codeFix({ + index: 0, + description: ts.Diagnostics.Add_missing_properties.message, + newRangeContent: +`f([{ + a: 0, + b: "" +}])`, +}); diff --git a/tests/cases/fourslash/codeFixAddMissingProperties31.ts b/tests/cases/fourslash/codeFixAddMissingProperties31.ts new file mode 100644 index 00000000000..c05e87d68d4 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingProperties31.ts @@ -0,0 +1,21 @@ +/// + +////interface A { +//// a: number; +//// b: string; +////} +////interface B { +//// c: A[]; +////} +////[|const b: B[] = [{c: [{}]}]|] + +debugger; +verify.codeFix({ + index: 0, + description: ts.Diagnostics.Add_missing_properties.message, + newRangeContent: +`const b: B[] = [{c: [{ + a: 0, + b: "" +}]}]`, +});