Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a8e1ad4

Browse filesBrowse files
authored
fix(37781): import missing argument types for a new method (microsoft#37857)
1 parent 5f46d42 commit a8e1ad4
Copy full SHA for a8e1ad4

6 files changed

+139-16Lines changed: 139 additions & 16 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/services/codefixes/fixAddMissingMember.ts‎

Copy file name to clipboardExpand all lines: src/services/codefixes/fixAddMissingMember.ts
+9-10Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ namespace ts.codefix {
2121
return [createCodeFixAction(fixName, changes, [Diagnostics.Add_missing_enum_member_0, token.text], fixId, Diagnostics.Add_all_missing_members)];
2222
}
2323
const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info;
24-
const methodCodeAction = call && getActionForMethodDeclaration(context, declSourceFile, parentDeclaration, token, call, makeStatic, inJs, context.preferences);
24+
const methodCodeAction = call && getActionForMethodDeclaration(context, declSourceFile, parentDeclaration, token, call, makeStatic, inJs);
2525
const addMember = inJs && !isInterfaceDeclaration(parentDeclaration) ?
2626
singleElementArray(getActionsForAddMissingMemberInJavascriptFile(context, declSourceFile, parentDeclaration, token, makeStatic)) :
2727
getActionsForAddMissingMemberInTypeScriptFile(context, declSourceFile, parentDeclaration, token, makeStatic);
2828
return concatenate(singleElementArray(methodCodeAction), addMember);
2929
},
3030
fixIds: [fixId],
3131
getAllCodeActions: context => {
32-
const { program, preferences } = context;
32+
const { program } = context;
3333
const checker = program.getTypeChecker();
3434
const seen = createMap<true>();
3535

@@ -66,7 +66,7 @@ namespace ts.codefix {
6666

6767
// Always prefer to add a method declaration if possible.
6868
if (call && !isPrivateIdentifier(token)) {
69-
addMethodDeclaration(context, changes, declSourceFile, parentDeclaration, token, call, makeStatic, inJs, preferences);
69+
addMethodDeclaration(context, changes, declSourceFile, parentDeclaration, token, call, makeStatic, inJs);
7070
}
7171
else {
7272
if (inJs && !isInterfaceDeclaration(parentDeclaration)) {
@@ -304,12 +304,11 @@ namespace ts.codefix {
304304
token: Identifier | PrivateIdentifier,
305305
callExpression: CallExpression,
306306
makeStatic: boolean,
307-
inJs: boolean,
308-
preferences: UserPreferences,
307+
inJs: boolean
309308
): CodeFixAction | undefined {
310309
// Private methods are not implemented yet.
311310
if (isPrivateIdentifier(token)) { return undefined; }
312-
const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(context, t, declSourceFile, classDeclaration, token, callExpression, makeStatic, inJs, preferences));
311+
const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(context, t, declSourceFile, classDeclaration, token, callExpression, makeStatic, inJs));
313312
return createCodeFixAction(fixName, changes, [makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0, token.text], fixId, Diagnostics.Add_all_missing_members);
314313
}
315314

@@ -321,18 +320,18 @@ namespace ts.codefix {
321320
token: Identifier,
322321
callExpression: CallExpression,
323322
makeStatic: boolean,
324-
inJs: boolean,
325-
preferences: UserPreferences,
323+
inJs: boolean
326324
): void {
327-
const methodDeclaration = createMethodFromCallExpression(context, callExpression, token.text, inJs, makeStatic, preferences, typeDecl);
325+
const importAdder = createImportAdder(declSourceFile, context.program, context.preferences, context.host);
326+
const methodDeclaration = createMethodFromCallExpression(context, callExpression, token.text, inJs, makeStatic, typeDecl, importAdder);
328327
const containingMethodDeclaration = getAncestor(callExpression, SyntaxKind.MethodDeclaration);
329-
330328
if (containingMethodDeclaration && containingMethodDeclaration.parent === typeDecl) {
331329
changeTracker.insertNodeAfter(declSourceFile, containingMethodDeclaration, methodDeclaration);
332330
}
333331
else {
334332
changeTracker.insertNodeAtClassStart(declSourceFile, typeDecl, methodDeclaration);
335333
}
334+
importAdder.writeFixes(changeTracker);
336335
}
337336

338337
function addEnumMemberDeclaration(changes: textChanges.ChangeTracker, checker: TypeChecker, token: Identifier, enumDeclaration: EnumDeclaration) {
Collapse file

‎src/services/codefixes/helpers.ts‎

Copy file name to clipboardExpand all lines: src/services/codefixes/helpers.ts
+15-5Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,16 +218,26 @@ namespace ts.codefix {
218218
methodName: string,
219219
inJs: boolean,
220220
makeStatic: boolean,
221-
preferences: UserPreferences,
222221
contextNode: Node,
222+
importAdder: ImportAdder
223223
): MethodDeclaration {
224224
const body = !isInterfaceDeclaration(contextNode);
225225
const { typeArguments, arguments: args, parent } = call;
226+
const scriptTarget = getEmitScriptTarget(context.program.getCompilerOptions());
226227
const checker = context.program.getTypeChecker();
227228
const tracker = getNoopSymbolTrackerWithResolver(context);
228-
const types = map(args, arg =>
229-
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
230-
checker.typeToTypeNode(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg)), contextNode, /*flags*/ undefined, tracker));
229+
const types = map(args, arg => {
230+
const type = checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg));
231+
const typeNode = checker.typeToTypeNode(type, contextNode, /*flags*/ undefined, tracker);
232+
if (typeNode?.kind === SyntaxKind.ImportType) {
233+
const importableReference = tryGetAutoImportableReferenceFromImportTypeNode(typeNode, type, scriptTarget);
234+
if (importableReference) {
235+
importSymbols(importAdder, importableReference.symbols);
236+
return importableReference.typeReference;
237+
}
238+
}
239+
return typeNode;
240+
});
231241
const names = map(args, arg =>
232242
isIdentifier(arg) ? arg.text : isPropertyAccessExpression(arg) && isIdentifier(arg.name) ? arg.name.text : undefined);
233243
const contextualType = checker.getContextualType(call);
@@ -242,7 +252,7 @@ namespace ts.codefix {
242252
createTypeParameterDeclaration(CharacterCodes.T + typeArguments!.length - 1 <= CharacterCodes.Z ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`)),
243253
/*parameters*/ createDummyParameters(args.length, names, types, /*minArgumentCount*/ undefined, inJs),
244254
/*type*/ returnType,
245-
body ? createStubbedMethodBody(preferences) : undefined);
255+
body ? createStubbedMethodBody(context.preferences) : undefined);
246256
}
247257

248258
function createDummyParameters(argCount: number, names: (string | undefined)[] | undefined, types: (TypeNode | undefined)[] | undefined, minArgumentCount: number | undefined, inJs: boolean): ParameterDeclaration[] {
Collapse file

‎tests/cases/fourslash/codeFixUndeclaredAcrossFiles3.ts‎

Copy file name to clipboardExpand all lines: tests/cases/fourslash/codeFixUndeclaredAcrossFiles3.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
verify.getAndApplyCodeFix(/*errorCode*/ undefined, 0);
2121

2222
verify.rangeIs(`
23-
m0(arg0: import("./f2").D) {
23+
m0(arg0: D) {
2424
throw new Error("Method not implemented.");
2525
}
2626
`);
Collapse file
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: a.ts
4+
////export interface A {
5+
//// x: number;
6+
////}
7+
////export function create(fn: (args: A) => void) {}
8+
9+
// @Filename: b.ts
10+
////import { create } from "./a";
11+
////class B {
12+
//// bar() {
13+
//// create(args => this.foo(args));
14+
//// }
15+
////}
16+
17+
goTo.file("b.ts");
18+
verify.codeFix({
19+
description: [ts.Diagnostics.Declare_method_0.message, "foo"],
20+
index: 0,
21+
newFileContent:
22+
`import { create, A } from "./a";
23+
class B {
24+
bar() {
25+
create(args => this.foo(args));
26+
}
27+
foo(args: A): void {
28+
throw new Error("Method not implemented.");
29+
}
30+
}`
31+
});
Collapse file
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: a.ts
4+
////export interface A {
5+
//// x: number;
6+
////}
7+
8+
// @Filename: b.ts
9+
////import { A } from "./a";
10+
////export interface B<T> {
11+
//// payload: T;
12+
////}
13+
////export function create(fn: (args: B<A>) => void) {}
14+
15+
// @Filename: c.ts
16+
////import { create } from "./b";
17+
////class C {
18+
//// bar() {
19+
//// create(args => this.foo(args));
20+
//// }
21+
////}
22+
23+
goTo.file("c.ts");
24+
verify.codeFix({
25+
description: [ts.Diagnostics.Declare_method_0.message, "foo"],
26+
index: 0,
27+
newFileContent:
28+
`import { create, B } from "./b";
29+
import { A } from "./a";
30+
class C {
31+
bar() {
32+
create(args => this.foo(args));
33+
}
34+
foo(args: B<A>): void {
35+
throw new Error("Method not implemented.");
36+
}
37+
}`
38+
});
Collapse file
+45Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: a.ts
4+
////export interface A {
5+
//// x: number;
6+
////}
7+
8+
// @Filename: b.ts
9+
////export interface B<T> {
10+
//// payload: T;
11+
////}
12+
13+
// @Filename: c.ts
14+
////import { A } from "./a";
15+
////import { B } from "./b";
16+
////export interface C<T> {
17+
//// payload: T;
18+
////}
19+
////export function create(fn: (args: C<B<A>>) => void) {}
20+
21+
// @Filename: d.ts
22+
////import { create } from "./c";
23+
////class D {
24+
//// bar() {
25+
//// create(args => this.foo(args));
26+
//// }
27+
////}
28+
29+
goTo.file("d.ts");
30+
verify.codeFix({
31+
description: [ts.Diagnostics.Declare_method_0.message, "foo"],
32+
index: 0,
33+
newFileContent:
34+
`import { create, C } from "./c";
35+
import { B } from "./b";
36+
import { A } from "./a";
37+
class D {
38+
bar() {
39+
create(args => this.foo(args));
40+
}
41+
foo(args: C<B<A>>): void {
42+
throw new Error("Method not implemented.");
43+
}
44+
}`
45+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.