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);