diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1979557243abb..186fc67a53962 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -7784,6 +7784,30 @@ "category": "Message", "code": 95187 }, + "Add missing parameter to '{0}'": { + "category": "Message", + "code": 95188 + }, + "Add missing parameters to '{0}'": { + "category": "Message", + "code": 95189 + }, + "Add all missing parameters": { + "category": "Message", + "code": 95190 + }, + "Add optional parameter to '{0}'": { + "category": "Message", + "code": 95191 + }, + "Add optional parameters to '{0}'": { + "category": "Message", + "code": 95192 + }, + "Add all optional parameters": { + "category": "Message", + "code": 95193 + }, "No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": { "category": "Error", diff --git a/src/services/_namespaces/ts.codefix.ts b/src/services/_namespaces/ts.codefix.ts index 3bf0c18cb9e5a..72b1cb87c50f7 100644 --- a/src/services/_namespaces/ts.codefix.ts +++ b/src/services/_namespaces/ts.codefix.ts @@ -31,6 +31,7 @@ export * from "../codefixes/fixSpelling"; export * from "../codefixes/returnValueCorrect"; export * from "../codefixes/fixAddMissingMember"; export * from "../codefixes/fixAddMissingNewOperator"; +export * from "../codefixes/fixAddMissingParam"; export * from "../codefixes/fixCannotFindModule"; export * from "../codefixes/fixClassDoesntImplementInheritedAbstractMember"; export * from "../codefixes/fixClassSuperMustPrecedeThisAccess"; diff --git a/src/services/codefixes/fixAddMissingParam.ts b/src/services/codefixes/fixAddMissingParam.ts new file mode 100644 index 0000000000000..bb64233781974 --- /dev/null +++ b/src/services/codefixes/fixAddMissingParam.ts @@ -0,0 +1,327 @@ +import { + append, + ArrowFunction, + CodeFixAction, + declarationNameToString, + Diagnostics, + factory, + filter, + findAncestor, + first, + forEach, + FunctionDeclaration, + FunctionExpression, + FunctionLikeDeclaration, + getNameOfAccessExpression, + getNameOfDeclaration, + getTokenAtPosition, + isAccessExpression, + isCallExpression, + isIdentifier, + isParameter, + isPropertyDeclaration, + isSourceFileFromLibrary, + isVariableDeclaration, + last, + lastOrUndefined, + length, + map, + MethodDeclaration, + Node, + NodeBuilderFlags, + ParameterDeclaration, + Program, + QuestionToken, + some, + SourceFile, + SyntaxKind, + textChanges, + Type, + TypeChecker, + TypeNode, +} from "../_namespaces/ts"; +import { + codeFixAll, + createCodeFixAction, + registerCodeFix, +} from "../_namespaces/ts.codefix"; + +const addMissingParamFixId = "addMissingParam"; +const addOptionalParamFixId = "addOptionalParam"; +const errorCodes = [Diagnostics.Expected_0_arguments_but_got_1.code]; + +registerCodeFix({ + errorCodes, + fixIds: [addMissingParamFixId, addOptionalParamFixId], + getCodeActions(context) { + const info = getInfo(context.sourceFile, context.program, context.span.start); + if (info === undefined) return undefined; + + const { name, declarations, newParameters, newOptionalParameters } = info; + const actions: CodeFixAction[] = []; + + if (length(newParameters)) { + append( + actions, + createCodeFixAction( + addMissingParamFixId, + textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declarations, newParameters)), + [length(newParameters) > 1 ? Diagnostics.Add_missing_parameters_to_0 : Diagnostics.Add_missing_parameter_to_0, name], + addMissingParamFixId, + Diagnostics.Add_all_missing_parameters, + ), + ); + } + + if (length(newOptionalParameters)) { + append( + actions, + createCodeFixAction( + addOptionalParamFixId, + textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declarations, newOptionalParameters)), + [length(newOptionalParameters) > 1 ? Diagnostics.Add_optional_parameters_to_0 : Diagnostics.Add_optional_parameter_to_0, name], + addOptionalParamFixId, + Diagnostics.Add_all_optional_parameters, + ), + ); + } + + return actions; + }, + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(context.sourceFile, context.program, diag.start); + if (info) { + const { declarations, newParameters, newOptionalParameters } = info; + if (context.fixId === addMissingParamFixId) { + doChange(changes, context.sourceFile, declarations, newParameters); + } + if (context.fixId === addOptionalParamFixId) { + doChange(changes, context.sourceFile, declarations, newOptionalParameters); + } + } + }), +}); + +type ConvertibleSignatureDeclaration = + | FunctionDeclaration + | FunctionExpression + | ArrowFunction + | MethodDeclaration; + +interface SignatureInfo { + readonly newParameters: ParameterInfo[]; + readonly newOptionalParameters: ParameterInfo[]; + readonly name: string; + readonly declarations: ConvertibleSignatureDeclaration[]; +} + +interface ParameterInfo { + readonly pos: number; + readonly declaration: ParameterDeclaration; +} + +function getInfo(sourceFile: SourceFile, program: Program, pos: number): SignatureInfo | undefined { + const token = getTokenAtPosition(sourceFile, pos); + const callExpression = findAncestor(token, isCallExpression); + if (callExpression === undefined || length(callExpression.arguments) === 0) { + return undefined; + } + + const checker = program.getTypeChecker(); + const type = checker.getTypeAtLocation(callExpression.expression); + const convertibleSignatureDeclarations = filter(type.symbol.declarations, isConvertibleSignatureDeclaration); + if (convertibleSignatureDeclarations === undefined) { + return undefined; + } + + const nonOverloadDeclaration = lastOrUndefined(convertibleSignatureDeclarations); + if ( + nonOverloadDeclaration === undefined || + nonOverloadDeclaration.body === undefined || + isSourceFileFromLibrary(program, nonOverloadDeclaration.getSourceFile()) + ) { + return undefined; + } + + const name = tryGetName(nonOverloadDeclaration); + if (name === undefined) { + return undefined; + } + + const newParameters: ParameterInfo[] = []; + const newOptionalParameters: ParameterInfo[] = []; + const parametersLength = length(nonOverloadDeclaration.parameters); + const argumentsLength = length(callExpression.arguments); + if (parametersLength > argumentsLength) { + return undefined; + } + + const declarations = [nonOverloadDeclaration, ...getOverloads(nonOverloadDeclaration, convertibleSignatureDeclarations)]; + for (let i = 0, pos = 0, paramIndex = 0; i < argumentsLength; i++) { + const arg = callExpression.arguments[i]; + const expr = isAccessExpression(arg) ? getNameOfAccessExpression(arg) : arg; + const type = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg))); + const parameter = pos < parametersLength ? nonOverloadDeclaration.parameters[pos] : undefined; + if ( + parameter && + checker.isTypeAssignableTo(type, checker.getTypeAtLocation(parameter)) + ) { + pos++; + continue; + } + + const name = expr && isIdentifier(expr) ? expr.text : `p${paramIndex++}`; + const typeNode = typeToTypeNode(checker, type, nonOverloadDeclaration); + append(newParameters, { + pos: i, + declaration: createParameter(name, typeNode, /*questionToken*/ undefined), + }); + + if (isOptionalPos(declarations, pos)) { + continue; + } + + append(newOptionalParameters, { + pos: i, + declaration: createParameter(name, typeNode, factory.createToken(SyntaxKind.QuestionToken)), + }); + } + + return { + newParameters, + newOptionalParameters, + name: declarationNameToString(name), + declarations, + }; +} + +function tryGetName(node: FunctionLikeDeclaration) { + const name = getNameOfDeclaration(node); + if (name) { + return name; + } + + if ( + isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) || + isPropertyDeclaration(node.parent) || + isParameter(node.parent) + ) { + return node.parent.name; + } +} + +function typeToTypeNode(checker: TypeChecker, type: Type, enclosingDeclaration: Node) { + return checker.typeToTypeNode(checker.getWidenedType(type), enclosingDeclaration, NodeBuilderFlags.NoTruncation) + ?? factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); +} + +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + declarations: ConvertibleSignatureDeclaration[], + newParameters: ParameterInfo[], +) { + forEach(declarations, declaration => { + if (length(declaration.parameters)) { + changes.replaceNodeRangeWithNodes( + sourceFile, + first(declaration.parameters), + last(declaration.parameters), + updateParameters(declaration, newParameters), + { + joiner: ", ", + indentation: 0, + leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, + trailingTriviaOption: textChanges.TrailingTriviaOption.Include, + }, + ); + } + else { + forEach(updateParameters(declaration, newParameters), (parameter, index) => { + if (length(declaration.parameters) === 0 && index === 0) { + changes.insertNodeAt(sourceFile, declaration.parameters.end, parameter); + } + else { + changes.insertNodeAtEndOfList(sourceFile, declaration.parameters, parameter); + } + }); + } + }); +} + +function isConvertibleSignatureDeclaration(node: Node): node is ConvertibleSignatureDeclaration { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.ArrowFunction: + return true; + default: + return false; + } +} + +function updateParameters(node: ConvertibleSignatureDeclaration, newParameters: readonly ParameterInfo[]) { + const parameters = map(node.parameters, p => + factory.createParameterDeclaration( + p.modifiers, + p.dotDotDotToken, + p.name, + p.questionToken, + p.type, + p.initializer, + )); + for (const { pos, declaration } of newParameters) { + const prev = pos > 0 ? parameters[pos - 1] : undefined; + parameters.splice( + pos, + 0, + factory.updateParameterDeclaration( + declaration, + declaration.modifiers, + declaration.dotDotDotToken, + declaration.name, + prev && prev.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : declaration.questionToken, + declaration.type, + declaration.initializer, + ), + ); + } + return parameters; +} + +function getOverloads(implementation: ConvertibleSignatureDeclaration, declarations: readonly ConvertibleSignatureDeclaration[]): ConvertibleSignatureDeclaration[] { + const overloads: ConvertibleSignatureDeclaration[] = []; + for (const declaration of declarations) { + if (isOverload(declaration)) { + if (length(declaration.parameters) === length(implementation.parameters)) { + overloads.push(declaration); + continue; + } + if (length(declaration.parameters) > length(implementation.parameters)) { + return []; + } + } + } + return overloads; +} + +function isOverload(declaration: ConvertibleSignatureDeclaration) { + return isConvertibleSignatureDeclaration(declaration) && declaration.body === undefined; +} + +function createParameter(name: string, type: TypeNode, questionToken: QuestionToken | undefined) { + return factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + name, + questionToken, + type, + /*initializer*/ undefined, + ); +} + +function isOptionalPos(declarations: ConvertibleSignatureDeclaration[], pos: number) { + return length(declarations) && some(declarations, d => pos < length(d.parameters) && !!d.parameters[pos] && d.parameters[pos].questionToken === undefined); +} diff --git a/tests/cases/fourslash/arityErrorAfterSignatureHelp.ts b/tests/cases/fourslash/arityErrorAfterSignatureHelp.ts index e6f80141a4a4d..943eeae5a3c7f 100644 --- a/tests/cases/fourslash/arityErrorAfterSignatureHelp.ts +++ b/tests/cases/fourslash/arityErrorAfterSignatureHelp.ts @@ -18,5 +18,5 @@ verify.signatureHelp({ kind: "retrigger" } }) -verify.not.codeFixAvailable() // trigger typecheck +verify.not.codeFixAvailable(); // trigger typecheck verify.errorExistsBetweenMarkers("1", "2"); diff --git a/tests/cases/fourslash/codeFixAddMissingParam1.ts b/tests/cases/fourslash/codeFixAddMissingParam1.ts new file mode 100644 index 0000000000000..2a340f6677a6c --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam1.ts @@ -0,0 +1,12 @@ +/// + +////[|function f() {}|] +//// +////const a = 1; +////f(a); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newRangeContent: "function f(a: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam10.ts b/tests/cases/fourslash/codeFixAddMissingParam10.ts new file mode 100644 index 0000000000000..e65f055082991 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam10.ts @@ -0,0 +1,13 @@ +/// + +////[|function f() {}|] +//// +////const a = 1; +////const b = ""; +////f(a, b, true); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameters_to_0.message, "f"], + index: 0, + newRangeContent: "function f(a: number, b: string, p0: boolean) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam11.ts b/tests/cases/fourslash/codeFixAddMissingParam11.ts new file mode 100644 index 0000000000000..d930c95fcdf4b --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam11.ts @@ -0,0 +1,14 @@ +/// + +////class C { +//// [|private p = () => {}|] +//// m(a: boolean) { +//// this.p(a); +//// } +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "p"], + index: 0, + newRangeContent: "private p = (a: boolean) => {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam12.ts b/tests/cases/fourslash/codeFixAddMissingParam12.ts new file mode 100644 index 0000000000000..5ac6b3ef370d9 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam12.ts @@ -0,0 +1,11 @@ +/// + +////function f([|cb = () => {}|]) { +//// cb(""); +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "cb"], + index: 0, + newRangeContent: "cb = (p0: string) => {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam13.ts b/tests/cases/fourslash/codeFixAddMissingParam13.ts new file mode 100644 index 0000000000000..4fab804873481 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam13.ts @@ -0,0 +1,20 @@ +/// + +////function f(a: string): string; +////function f(a: string, b: number): string; +////function f(a: string, b?: number): string { +//// return ""; +////} +////f("", 1, ""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newFileContent: +`function f(a: string): string; +function f(a: string, b: number, p0: string): string; +function f(a: string, b?: number, p0?: string): string { + return ""; +} +f("", 1, "");` +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam14.ts b/tests/cases/fourslash/codeFixAddMissingParam14.ts new file mode 100644 index 0000000000000..fc9d46c8016be --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam14.ts @@ -0,0 +1,20 @@ +/// + +////function f(a: string): string; +////function f(a: string, b: number): string; +////function f(a: string, b?: number): string { +//// return ""; +////} +////f("", "", 1); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newFileContent: +`function f(a: string): string; +function f(a: string, p0: string, b: number): string; +function f(a: string, p0: string, b?: number): string { + return ""; +} +f("", "", 1);` +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam15.ts b/tests/cases/fourslash/codeFixAddMissingParam15.ts new file mode 100644 index 0000000000000..17d2d52e43911 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam15.ts @@ -0,0 +1,6 @@ +/// + +////function f(a: number, b: number) {} +////f(); + +verify.not.codeFixAvailable("addMissingParam"); diff --git a/tests/cases/fourslash/codeFixAddMissingParam16.ts b/tests/cases/fourslash/codeFixAddMissingParam16.ts new file mode 100644 index 0000000000000..bdf5e13527962 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam16.ts @@ -0,0 +1,20 @@ +/// + +////function f(a: string, b: string): string +////function f(a: number, b: number): number +////function f(a: number | string, b: number | string): number | string { +//// return a + b; +////} +////f(1, 2, "") + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newFileContent: +`function f(a: string, b: string, p0: string): string +function f(a: number, b: number, p0: string): number +function f(a: number | string, b: number | string, p0: string): number | string { + return a + b; +} +f(1, 2, "")` +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam2.ts b/tests/cases/fourslash/codeFixAddMissingParam2.ts new file mode 100644 index 0000000000000..0c8d07b119070 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam2.ts @@ -0,0 +1,13 @@ +/// + +////[|function f(a: number) {}|] +//// +////const a = 1; +////const b = 1; +////f(a, b); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newRangeContent: "function f(a: number, b: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam3.ts b/tests/cases/fourslash/codeFixAddMissingParam3.ts new file mode 100644 index 0000000000000..632c56edaf35d --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam3.ts @@ -0,0 +1,16 @@ +/// + +////class C { +//// private a = 1; +//// +//// [|m1() {}|] +//// m2() { +//// this.m1(this.a); +//// } +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "m1"], + index: 0, + newRangeContent: "m1(a: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam4.ts b/tests/cases/fourslash/codeFixAddMissingParam4.ts new file mode 100644 index 0000000000000..e62de1d634fce --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam4.ts @@ -0,0 +1,11 @@ +/// + +////[|function f() {}|] +//// +////f(""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newRangeContent: "function f(p0: string) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam5.ts b/tests/cases/fourslash/codeFixAddMissingParam5.ts new file mode 100644 index 0000000000000..690d3726c711d --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam5.ts @@ -0,0 +1,11 @@ +/// + +////[|const f = function () {}|] +//// +////f(""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newRangeContent: "const f = function (p0: string) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam6.ts b/tests/cases/fourslash/codeFixAddMissingParam6.ts new file mode 100644 index 0000000000000..da8f445cb9814 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam6.ts @@ -0,0 +1,11 @@ +/// + +////[|const f = () => {}|] +//// +////f(""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"], + index: 0, + newRangeContent: "const f = (p0: string) => {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam7.ts b/tests/cases/fourslash/codeFixAddMissingParam7.ts new file mode 100644 index 0000000000000..c9d14dcb211e5 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam7.ts @@ -0,0 +1,14 @@ +/// + +////class C { +//// [|m1() {}|] +//// m2(a: boolean) { +//// this.m1(a); +//// } +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "m1"], + index: 0, + newRangeContent: "m1(a: boolean) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam8.ts b/tests/cases/fourslash/codeFixAddMissingParam8.ts new file mode 100644 index 0000000000000..55e3931a49b25 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam8.ts @@ -0,0 +1,14 @@ +/// + +////[|function f(a: number) {}|] +//// +////const a = 1; +////const b = 1; +////const c = 1; +////f(a, b, c); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameters_to_0.message, "f"], + index: 0, + newRangeContent: "function f(a: number, b: number, c: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam9.ts b/tests/cases/fourslash/codeFixAddMissingParam9.ts new file mode 100644 index 0000000000000..dc73f2e494ce8 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam9.ts @@ -0,0 +1,10 @@ +/// + +////[|function f() {}|] +////f("", { x: 1 }, [ "" ], true); + +verify.codeFix({ + description: [ts.Diagnostics.Add_missing_parameters_to_0.message, "f"], + index: 0, + newRangeContent: "function f(p0: string, p1: { x: number; }, p2: string[], p3: boolean) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddMissingParam_all.ts b/tests/cases/fourslash/codeFixAddMissingParam_all.ts new file mode 100644 index 0000000000000..09fb31ee0beb2 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingParam_all.ts @@ -0,0 +1,52 @@ +/// + +////[|function f1() {}|] +//// +////const a = 1; +////const b = ""; +////f1(a, b, true); +//// +////function f2() {} +////f2("", { x: 1 }, [ "" ], true); +//// +////class C { +//// [|m1() {}|] +//// m2(a: boolean) { +//// this.m1(a); +//// } +////} +//// +////function f3(a: string): string; +////function f3(a: string, b: number): string; +////function f3(a: string, b?: number): string { +//// return ""; +////} +////f3("", "", 1); + +verify.codeFixAll({ + fixId: "addMissingParam", + fixAllDescription: ts.Diagnostics.Add_all_missing_parameters.message, + newFileContent: +`function f1(a: number, b: string, p0: boolean) {} + +const a = 1; +const b = ""; +f1(a, b, true); + +function f2(p0: string, p1: { x: number; }, p2: string[], p3: boolean) {} +f2("", { x: 1 }, [ "" ], true); + +class C { + m1(a: boolean) {} + m2(a: boolean) { + this.m1(a); + } +} + +function f3(a: string): string; +function f3(a: string, p0: string, b: number): string; +function f3(a: string, p0: string, b?: number): string { + return ""; +} +f3("", "", 1);` +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam1.ts b/tests/cases/fourslash/codeFixAddOptionalParam1.ts new file mode 100644 index 0000000000000..49c631484b2e7 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam1.ts @@ -0,0 +1,12 @@ +/// + +////[|function f() {}|] +//// +////const a = 1; +////f(a); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newRangeContent: "function f(a?: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam10.ts b/tests/cases/fourslash/codeFixAddOptionalParam10.ts new file mode 100644 index 0000000000000..951a0c4eea897 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam10.ts @@ -0,0 +1,13 @@ +/// + +////[|function f() {}|] +//// +////const a = 1; +////const b = ""; +////f(a, b, true); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameters_to_0.message, "f"], + index: 1, + newRangeContent: "function f(a?: number, b?: string, p0?: boolean) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam11.ts b/tests/cases/fourslash/codeFixAddOptionalParam11.ts new file mode 100644 index 0000000000000..e313df4d450c9 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam11.ts @@ -0,0 +1,14 @@ +/// + +////class C { +//// [|private p = () => {}|] +//// m(a: boolean) { +//// this.p(a); +//// } +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "p"], + index: 1, + newRangeContent: "private p = (a?: boolean) => {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam12.ts b/tests/cases/fourslash/codeFixAddOptionalParam12.ts new file mode 100644 index 0000000000000..19253c555d93b --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam12.ts @@ -0,0 +1,11 @@ +/// + +////function f([|cb = () => {}|]) { +//// cb(""); +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "cb"], + index: 1, + newRangeContent: "cb = (p0?: string) => {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam13.ts b/tests/cases/fourslash/codeFixAddOptionalParam13.ts new file mode 100644 index 0000000000000..0809bfafba894 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam13.ts @@ -0,0 +1,20 @@ +/// + +////function f(a: string): string; +////function f(a: string, b: number): string; +////function f(a: string, b?: number): string { +//// return ""; +////} +////f("", 1, ""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newFileContent: +`function f(a: string): string; +function f(a: string, b: number, p0?: string): string; +function f(a: string, b?: number, p0?: string): string { + return ""; +} +f("", 1, "");` +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam14.ts b/tests/cases/fourslash/codeFixAddOptionalParam14.ts new file mode 100644 index 0000000000000..09d4f0818b5cd --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam14.ts @@ -0,0 +1,10 @@ +/// + +////function f(a: string): string; +////function f(a: string, b: number): string; +////function f(a: string, b?: number): string { +//// return ""; +////} +////f("", "", 1); + +verify.not.codeFixAvailable("addOptionalParam"); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam15.ts b/tests/cases/fourslash/codeFixAddOptionalParam15.ts new file mode 100644 index 0000000000000..6f4e37596a352 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam15.ts @@ -0,0 +1,6 @@ +/// + +////function f(a: number, b: number) {} +////f(); + +verify.not.codeFixAvailable("addOptionalParam"); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam16.ts b/tests/cases/fourslash/codeFixAddOptionalParam16.ts new file mode 100644 index 0000000000000..dd618a624cd02 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam16.ts @@ -0,0 +1,20 @@ +/// + +////function f(a: string): string; +////function f(a: string, b?: number): string; +////function f(a: string, b?: number): string { +//// return ""; +////} +////f("", "", 1); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newFileContent: +`function f(a: string): string; +function f(a: string, p0?: string, b?: number): string; +function f(a: string, p0?: string, b?: number): string { + return ""; +} +f("", "", 1);` +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam17.ts b/tests/cases/fourslash/codeFixAddOptionalParam17.ts new file mode 100644 index 0000000000000..2b55e9002297c --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam17.ts @@ -0,0 +1,20 @@ +/// + +////function f(a: string, b: string): string +////function f(a: number, b: number): number +////function f(a: number | string, b: number | string): number | string { +//// return a + b; +////} +////f(1, 2, "") + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newFileContent: +`function f(a: string, b: string, p0?: string): string +function f(a: number, b: number, p0?: string): number +function f(a: number | string, b: number | string, p0?: string): number | string { + return a + b; +} +f(1, 2, "")` +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam18.ts b/tests/cases/fourslash/codeFixAddOptionalParam18.ts new file mode 100644 index 0000000000000..fdedd4cc0abca --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam18.ts @@ -0,0 +1,6 @@ +/// + +////[|function f(a: number, c: string) {}|] +////f(1, 1, ""); + +verify.not.codeFixAvailable("addOptionalParam"); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam2.ts b/tests/cases/fourslash/codeFixAddOptionalParam2.ts new file mode 100644 index 0000000000000..29304cb0dd210 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam2.ts @@ -0,0 +1,13 @@ +/// + +////[|function f(a: number) {}|] +//// +////const a = 1; +////const b = 1; +////f(a, b); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newRangeContent: "function f(a: number, b?: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam3.ts b/tests/cases/fourslash/codeFixAddOptionalParam3.ts new file mode 100644 index 0000000000000..f86634c136e34 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam3.ts @@ -0,0 +1,16 @@ +/// + +////class C { +//// private a = 1; +//// +//// [|m1() {}|] +//// m2() { +//// this.m1(this.a); +//// } +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "m1"], + index: 1, + newRangeContent: "m1(a?: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam4.ts b/tests/cases/fourslash/codeFixAddOptionalParam4.ts new file mode 100644 index 0000000000000..6572fe70b8727 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam4.ts @@ -0,0 +1,11 @@ +/// + +////[|function f() {}|] +//// +////f(""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newRangeContent: "function f(p0?: string) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam5.ts b/tests/cases/fourslash/codeFixAddOptionalParam5.ts new file mode 100644 index 0000000000000..7ee52d6852391 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam5.ts @@ -0,0 +1,11 @@ +/// + +////[|const f = function () {}|] +//// +////f(""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newRangeContent: "const f = function (p0?: string) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam6.ts b/tests/cases/fourslash/codeFixAddOptionalParam6.ts new file mode 100644 index 0000000000000..60109211a6514 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam6.ts @@ -0,0 +1,11 @@ +/// + +////[|const f = () => {}|] +//// +////f(""); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"], + index: 1, + newRangeContent: "const f = (p0?: string) => {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam7.ts b/tests/cases/fourslash/codeFixAddOptionalParam7.ts new file mode 100644 index 0000000000000..d18947d35998c --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam7.ts @@ -0,0 +1,14 @@ +/// + +////class C { +//// [|m1() {}|] +//// m2(a: boolean) { +//// this.m1(a); +//// } +////} + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "m1"], + index: 1, + newRangeContent: "m1(a?: boolean) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam8.ts b/tests/cases/fourslash/codeFixAddOptionalParam8.ts new file mode 100644 index 0000000000000..c7f78753425f9 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam8.ts @@ -0,0 +1,14 @@ +/// + +////[|function f(a: number) {}|] +//// +////const a = 1; +////const b = 1; +////const c = 1; +////f(a, b, c); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameters_to_0.message, "f"], + index: 1, + newRangeContent: "function f(a: number, b?: number, c?: number) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam9.ts b/tests/cases/fourslash/codeFixAddOptionalParam9.ts new file mode 100644 index 0000000000000..077cfc02e973a --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam9.ts @@ -0,0 +1,10 @@ +/// + +////[|function f() {}|] +////f("", { x: 1 }, [ "" ], true); + +verify.codeFix({ + description: [ts.Diagnostics.Add_optional_parameters_to_0.message, "f"], + index: 1, + newRangeContent: "function f(p0?: string, p1?: { x: number; }, p2?: string[], p3?: boolean) {}" +}); diff --git a/tests/cases/fourslash/codeFixAddOptionalParam_all.ts b/tests/cases/fourslash/codeFixAddOptionalParam_all.ts new file mode 100644 index 0000000000000..e5eae49e19e41 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddOptionalParam_all.ts @@ -0,0 +1,52 @@ +/// + +////[|function f1() {}|] +//// +////const a = 1; +////const b = ""; +////f1(a, b, true); +//// +////function f2() {} +////f2("", { x: 1 }, [ "" ], true); +//// +////class C { +//// [|m1() {}|] +//// m2(a: boolean) { +//// this.m1(a); +//// } +////} +//// +////function f3(a: string): string; +////function f3(a: string, b?: number): string; +////function f3(a: string, b?: number): string { +//// return ""; +////} +////f3("", "", 1); + +verify.codeFixAll({ + fixId: "addOptionalParam", + fixAllDescription: ts.Diagnostics.Add_all_optional_parameters.message, + newFileContent: +`function f1(a?: number, b?: string, p0?: boolean) {} + +const a = 1; +const b = ""; +f1(a, b, true); + +function f2(p0?: string, p1?: { x: number; }, p2?: string[], p3?: boolean) {} +f2("", { x: 1 }, [ "" ], true); + +class C { + m1(a?: boolean) {} + m2(a: boolean) { + this.m1(a); + } +} + +function f3(a: string): string; +function f3(a: string, p0?: string, b?: number): string; +function f3(a: string, p0?: string, b?: number): string { + return ""; +} +f3("", "", 1);` +}); diff --git a/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts b/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts index f59d1bc190758..0c01fa47b0990 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageCallBodyBoth.ts @@ -13,4 +13,4 @@ ////f(new C()) -verify.rangeAfterCodeFix("x: number | C, y: undefined",/*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 0); +verify.rangeAfterCodeFix("x: number | C, y: undefined",/*includeWhiteSpace*/ undefined, /*errorCode*/ undefined, 1);