feat(51870): Add a Quick Fix to add an additional parameter to a method or function (#56411)

This commit is contained in:
Oleksandr T 2024-01-19 19:35:33 +02:00 committed by GitHub
parent 55153b0274
commit 140fa7e5d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 906 additions and 2 deletions

View File

@ -7792,6 +7792,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",

View File

@ -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";

View File

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

View File

@ -18,5 +18,5 @@ verify.signatureHelp({
kind: "retrigger"
}
})
verify.not.codeFixAvailable() // trigger typecheck
verify.not.codeFixAvailable(); // trigger typecheck
verify.errorExistsBetweenMarkers("1", "2");

View File

@ -0,0 +1,12 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,13 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////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) => {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////function f([|cb = () => {}|]) {
//// cb("");
////}
verify.codeFix({
description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "cb"],
index: 0,
newRangeContent: "cb = (p0: string) => {}"
});

View File

@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
////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, "");`
});

View File

@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
////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);`
});

View File

@ -0,0 +1,6 @@
/// <reference path="fourslash.ts" />
////function f(a: number, b: number) {}
////f();
verify.not.codeFixAvailable("addMissingParam");

View File

@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
////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, "")`
});

View File

@ -0,0 +1,13 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />
////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) {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////[|function f() {}|]
////
////f("");
verify.codeFix({
description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"],
index: 0,
newRangeContent: "function f(p0: string) {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////[|const f = function () {}|]
////
////f("");
verify.codeFix({
description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"],
index: 0,
newRangeContent: "const f = function (p0: string) {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////[|const f = () => {}|]
////
////f("");
verify.codeFix({
description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"],
index: 0,
newRangeContent: "const f = (p0: string) => {}"
});

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////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) {}"
});

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,10 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,52 @@
/// <reference path='fourslash.ts' />
////[|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);`
});

View File

@ -0,0 +1,12 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,13 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////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) => {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////function f([|cb = () => {}|]) {
//// cb("");
////}
verify.codeFix({
description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "cb"],
index: 1,
newRangeContent: "cb = (p0?: string) => {}"
});

View File

@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
////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, "");`
});

View File

@ -0,0 +1,10 @@
/// <reference path="fourslash.ts" />
////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");

View File

@ -0,0 +1,6 @@
/// <reference path="fourslash.ts" />
////function f(a: number, b: number) {}
////f();
verify.not.codeFixAvailable("addOptionalParam");

View File

@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
////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);`
});

View File

@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
////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, "")`
});

View File

@ -0,0 +1,6 @@
/// <reference path="fourslash.ts" />
////[|function f(a: number, c: string) {}|]
////f(1, 1, "");
verify.not.codeFixAvailable("addOptionalParam");

View File

@ -0,0 +1,13 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,16 @@
/// <reference path="fourslash.ts" />
////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) {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////[|function f() {}|]
////
////f("");
verify.codeFix({
description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"],
index: 1,
newRangeContent: "function f(p0?: string) {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////[|const f = function () {}|]
////
////f("");
verify.codeFix({
description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"],
index: 1,
newRangeContent: "const f = function (p0?: string) {}"
});

View File

@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />
////[|const f = () => {}|]
////
////f("");
verify.codeFix({
description: [ts.Diagnostics.Add_optional_parameter_to_0.message, "f"],
index: 1,
newRangeContent: "const f = (p0?: string) => {}"
});

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////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) {}"
});

View File

@ -0,0 +1,14 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,10 @@
/// <reference path="fourslash.ts" />
////[|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) {}"
});

View File

@ -0,0 +1,52 @@
/// <reference path='fourslash.ts' />
////[|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);`
});

View File

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