mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Improve testing of code fixes, and improve diagnostic messages (#18742)
* Improve testing of code fixes, and improve diagnostic messages * Disambiguate `newFileContent` from `newRangeContent`
This commit is contained in:
@@ -3689,6 +3689,10 @@
|
||||
"category": "Message",
|
||||
"code": 90026
|
||||
},
|
||||
"Declare static property '{0}'.": {
|
||||
"category": "Message",
|
||||
"code": 90027
|
||||
},
|
||||
|
||||
"Convert function to an ES2015 class": {
|
||||
"category": "Message",
|
||||
|
||||
@@ -2337,6 +2337,39 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyCodeFix(options: FourSlashInterface.VerifyCodeFixOptions) {
|
||||
const fileName = this.activeFile.fileName;
|
||||
const actions = this.getCodeFixActions(fileName, options.errorCode);
|
||||
let index = options.index;
|
||||
if (index === undefined) {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
else {
|
||||
if (!(actions && actions.length >= index + 1)) {
|
||||
this.raiseError(`Should find at least ${index + 1} codefix(es), but ${actions ? actions.length : "none"} found.`);
|
||||
}
|
||||
}
|
||||
|
||||
const action = actions[index];
|
||||
|
||||
assert.equal(action.description, options.description);
|
||||
|
||||
for (const change of action.changes) {
|
||||
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
|
||||
if (options.newFileContent) {
|
||||
assert(!options.newRangeContent);
|
||||
this.verifyCurrentFileContent(options.newFileContent);
|
||||
}
|
||||
else {
|
||||
this.verifyRangeIs(options.newRangeContent, /*includeWhitespace*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found.
|
||||
* @param fileName Path to file where error should be retrieved from.
|
||||
@@ -3716,6 +3749,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifySpanOfEnclosingComment(this.negative, onlyMultiLineDiverges);
|
||||
}
|
||||
|
||||
public codeFix(options: FourSlashInterface.VerifyCodeFixOptions) {
|
||||
this.state.verifyCodeFix(options);
|
||||
}
|
||||
|
||||
public codeFixAvailable() {
|
||||
this.state.verifyCodeFixAvailable(this.negative);
|
||||
}
|
||||
@@ -4359,4 +4396,13 @@ namespace FourSlashInterface {
|
||||
export interface CompletionsAtOptions {
|
||||
isNewIdentifierLocation?: boolean;
|
||||
}
|
||||
|
||||
export interface VerifyCodeFixOptions {
|
||||
description: string;
|
||||
// One of these should be defined.
|
||||
newFileContent?: string;
|
||||
newRangeContent?: string;
|
||||
errorCode?: number;
|
||||
index?: number;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +156,9 @@ namespace ts.codefix {
|
||||
const propertyChangeTracker = textChanges.ChangeTracker.fromContext(context);
|
||||
propertyChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, property, { suffix: context.newLineCharacter });
|
||||
|
||||
(actions || (actions = [])).push({
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Declare_property_0), [tokenName]),
|
||||
const diag = makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0;
|
||||
actions = append(actions, {
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(diag), [tokenName]),
|
||||
changes: propertyChangeTracker.getChanges()
|
||||
});
|
||||
|
||||
@@ -197,11 +198,9 @@ namespace ts.codefix {
|
||||
|
||||
const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromContext(context);
|
||||
methodDeclarationChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, methodDeclaration, { suffix: context.newLineCharacter });
|
||||
const diag = makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0;
|
||||
return {
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(makeStatic ?
|
||||
Diagnostics.Declare_method_0 :
|
||||
Diagnostics.Declare_static_method_0),
|
||||
[tokenName]),
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(diag), [tokenName]),
|
||||
changes: methodDeclarationChangeTracker.getChanges()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
//// |]}
|
||||
////}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
verify.codeFix({
|
||||
description: "Add 'this.' to unresolved variable.",
|
||||
newRangeContent: `
|
||||
this.foo = 10;
|
||||
`, /*includeWhitespace*/ true);
|
||||
`
|
||||
});
|
||||
|
||||
@@ -6,4 +6,7 @@
|
||||
//// bar() { [|foo = 10|] };
|
||||
////}
|
||||
|
||||
verify.rangeAfterCodeFix("this.foo = 10");
|
||||
verify.codeFix({
|
||||
description: "Add 'this.' to unresolved variable.",
|
||||
newRangeContent: "this.foo = 10",
|
||||
});
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////[|class C {
|
||||
////class C {
|
||||
//// method() {
|
||||
//// this.foo = 10;
|
||||
//// }
|
||||
////}|]
|
||||
////}
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
foo: number;
|
||||
verify.codeFix({
|
||||
description: "Declare property 'foo'.",
|
||||
index: 0,
|
||||
// TODO: GH#18445
|
||||
newFileContent: `class C {
|
||||
foo: number;\r
|
||||
method() {
|
||||
this.foo = 10;
|
||||
}
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
||||
}`
|
||||
});
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////[|class C {
|
||||
////class C {
|
||||
//// method() {
|
||||
//// this.foo = 10;
|
||||
//// }
|
||||
////}|]
|
||||
////}
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
[x:string]: number;
|
||||
verify.codeFix({
|
||||
description: "Add index signature for property 'foo'.",
|
||||
index: 1,
|
||||
// TODO: GH#18445
|
||||
newFileContent: `class C {
|
||||
[x: string]: number;\r
|
||||
method() {
|
||||
this.foo = 10;
|
||||
}
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 1);
|
||||
}`
|
||||
});
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////[|class C {
|
||||
////class C {
|
||||
//// static method() {
|
||||
//// this.foo = 10;
|
||||
//// }
|
||||
////}|]
|
||||
////}
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
static foo: number;
|
||||
verify.codeFix({
|
||||
description: "Declare static property 'foo'.",
|
||||
index: 0,
|
||||
// TODO: GH#18445
|
||||
newFileContent: `class C {
|
||||
static foo: number;\r
|
||||
static method() {
|
||||
this.foo = 10;
|
||||
}
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
||||
}`
|
||||
});
|
||||
|
||||
@@ -4,19 +4,25 @@
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
////class C {
|
||||
//// constructor() {
|
||||
//// }
|
||||
//// method() {
|
||||
//// this.foo === 10;
|
||||
//// }
|
||||
////}|]
|
||||
////}
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
verify.codeFix({
|
||||
description: "Initialize property 'foo' in the constructor.",
|
||||
index: 0,
|
||||
// TODO: GH#18741 and GH#18445
|
||||
newFileContent: `class C {
|
||||
constructor() {
|
||||
this.foo = undefined;
|
||||
\r
|
||||
this.foo = undefined;\r
|
||||
}
|
||||
method() {
|
||||
this.foo === 10;
|
||||
}
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
||||
}`
|
||||
});
|
||||
|
||||
@@ -4,17 +4,20 @@
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
////class C {
|
||||
//// static method() {
|
||||
//// ()=>{ this.foo === 10 };
|
||||
//// }
|
||||
////}
|
||||
////|]
|
||||
|
||||
verify.getAndApplyCodeFix(/*errorCode*/ undefined, /*index*/ 0);
|
||||
verify.currentFileContentIs(`class C {
|
||||
verify.codeFix({
|
||||
description: "Initialize static property 'foo'.",
|
||||
index: 0,
|
||||
// TODO: GH#18743 and GH#18445
|
||||
newFileContent: `class C {
|
||||
static method() {
|
||||
()=>{ this.foo === 10 };
|
||||
}
|
||||
}
|
||||
C.foo = undefined;` + "\r\n"); // TODO: GH#18445
|
||||
}C.foo = undefined;\r
|
||||
`
|
||||
});
|
||||
|
||||
@@ -4,15 +4,21 @@
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
////class C {
|
||||
//// constructor() {
|
||||
//// }
|
||||
//// prop = ()=>{ this.foo === 10 };
|
||||
////}|]
|
||||
////}
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
verify.codeFix({
|
||||
description: "Initialize property 'foo' in the constructor.",
|
||||
index: 0,
|
||||
// TODO: GH#18741 and GH#18445
|
||||
newFileContent: `class C {
|
||||
constructor() {
|
||||
this.foo = undefined;
|
||||
}
|
||||
\r
|
||||
this.foo = undefined;\r
|
||||
}
|
||||
prop = ()=>{ this.foo === 10 };
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
||||
}`
|
||||
});
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
////class C {
|
||||
//// static p = ()=>{ this.foo === 10 };
|
||||
////}
|
||||
////|]
|
||||
|
||||
verify.getAndApplyCodeFix(/*errorCode*/ undefined, /*index*/ 2)
|
||||
verify.currentFileContentIs(`class C {
|
||||
verify.codeFix({
|
||||
description: "Initialize static property 'foo'.",
|
||||
index: 2,
|
||||
// TODO: GH#18743 and GH#18445
|
||||
newFileContent: `class C {
|
||||
static p = ()=>{ this.foo === 10 };
|
||||
}
|
||||
C.foo = undefined;` + "\r\n"); // TODO: GH#18445
|
||||
}C.foo = undefined;\r
|
||||
`
|
||||
});
|
||||
|
||||
@@ -9,18 +9,55 @@
|
||||
//// }
|
||||
//// }
|
||||
|
||||
verify.getAndApplyCodeFix(/*errorCode*/undefined, 0);
|
||||
verify.getAndApplyCodeFix(/*errorCode*/undefined, 0);
|
||||
verify.getAndApplyCodeFix(/*errorCode*/undefined, 0);
|
||||
verify.getAndApplyCodeFix(/*errorCode*/undefined, 0);
|
||||
verify.codeFix({
|
||||
description: "Declare static method 'm1'.",
|
||||
index: 0,
|
||||
// TODO: GH#18445
|
||||
newRangeContent: `
|
||||
static m1(arg0: any, arg1: any, arg2: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
`,
|
||||
});
|
||||
|
||||
verify.rangeIs(`
|
||||
static prop2: string;
|
||||
static prop1: number;
|
||||
static m2(arg0: any, arg1: any): any {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
static m1(arg0: any, arg1: any, arg2: any): any {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
verify.codeFix({
|
||||
description: "Declare static method 'm2'.",
|
||||
index: 0,
|
||||
newRangeContent: `
|
||||
static m2(arg0: any, arg1: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
static m1(arg0: any, arg1: any, arg2: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
`,
|
||||
});
|
||||
|
||||
verify.codeFix({
|
||||
description: "Declare static property 'prop1'.",
|
||||
index: 0,
|
||||
newRangeContent: `
|
||||
static prop1: number;\r
|
||||
static m2(arg0: any, arg1: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
static m1(arg0: any, arg1: any, arg2: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
`,
|
||||
});
|
||||
|
||||
verify.codeFix({
|
||||
description: "Declare static property 'prop2'.",
|
||||
index: 0,
|
||||
newRangeContent: `
|
||||
static prop2: string;\r
|
||||
static prop1: number;\r
|
||||
static m2(arg0: any, arg1: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
static m1(arg0: any, arg1: any, arg2: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -10,18 +10,42 @@
|
||||
//// }
|
||||
//// }
|
||||
|
||||
verify.getAndApplyCodeFix(/*errorCode*/undefined, 0);
|
||||
verify.getAndApplyCodeFix(/*errorCode*/undefined, 0);
|
||||
verify.getAndApplyCodeFix(/*errorCode*/undefined, 0);
|
||||
verify.codeFix({
|
||||
description: "Declare method 'foo1'.",
|
||||
index: 0,
|
||||
// TODO: GH#18445
|
||||
newRangeContent: `
|
||||
foo1(arg0: any, arg1: any, arg2: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
`,
|
||||
});
|
||||
|
||||
verify.rangeIs(`
|
||||
foo3<T0, T1, T2, T3, T4, T5, T6, T7>(): any {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
foo2<T, U, V, W, X, Y, Z>(): any {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
foo1(arg0: any, arg1: any, arg2: any): any {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
verify.codeFix({
|
||||
description: "Declare method 'foo2'.",
|
||||
index: 0,
|
||||
newRangeContent: `
|
||||
foo2<T, U, V, W, X, Y, Z>(): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
foo1(arg0: any, arg1: any, arg2: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
`
|
||||
});
|
||||
|
||||
verify.codeFix({
|
||||
description: "Declare method 'foo3'.",
|
||||
index: 0,
|
||||
newRangeContent:`
|
||||
foo3<T0, T1, T2, T3, T4, T5, T6, T7>(): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
foo2<T, U, V, W, X, Y, Z>(): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
foo1(arg0: any, arg1: any, arg2: any): any {\r
|
||||
throw new Error("Method not implemented.");\r
|
||||
}\r
|
||||
`
|
||||
});
|
||||
|
||||
@@ -155,6 +155,13 @@ declare namespace FourSlashInterface {
|
||||
implementationListIsEmpty(): void;
|
||||
isValidBraceCompletionAtPosition(openingBrace?: string): void;
|
||||
isInCommentAtPosition(onlyMultiLineDiverges?: boolean): void;
|
||||
codeFix(options: {
|
||||
description: string,
|
||||
newFileContent?: string,
|
||||
newRangeContent?: string,
|
||||
errorCode?: number,
|
||||
index?: number,
|
||||
});
|
||||
codeFixAvailable(): void;
|
||||
applicableRefactorAvailableAtMarker(markerName: string): void;
|
||||
codeFixDiagnosticsAvailableAtMarkers(markerNames: string[], diagnosticCode?: number): void;
|
||||
|
||||
Reference in New Issue
Block a user