Skip to content

Commit dc316af

Browse files
authored
fix(58360): Cheese being inserted on TypeScript Quick Fix (microsoft#58365)
1 parent c763c27 commit dc316af

2 files changed

Lines changed: 64 additions & 9 deletions

File tree

src/services/codefixes/fixAddMissingParam.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
FunctionDeclaration,
1313
FunctionExpression,
1414
FunctionLikeDeclaration,
15+
getEmitScriptTarget,
1516
getNameOfAccessExpression,
1617
getNameOfDeclaration,
18+
getSourceFileOfNode,
1719
getTokenAtPosition,
1820
isAccessExpression,
1921
isCallExpression,
@@ -22,6 +24,7 @@ import {
2224
isPropertyDeclaration,
2325
isSourceFileFromLibrary,
2426
isVariableDeclaration,
27+
LanguageServiceHost,
2528
last,
2629
lastOrUndefined,
2730
length,
@@ -32,18 +35,24 @@ import {
3235
ParameterDeclaration,
3336
Program,
3437
QuestionToken,
38+
ScriptTarget,
3539
some,
3640
SourceFile,
3741
SyntaxKind,
3842
textChanges,
3943
Type,
4044
TypeChecker,
4145
TypeNode,
46+
UserPreferences,
4247
} from "../_namespaces/ts";
4348
import {
4449
codeFixAll,
4550
createCodeFixAction,
51+
createImportAdder,
52+
ImportAdder,
53+
importSymbols,
4654
registerCodeFix,
55+
tryGetAutoImportableReferenceFromTypeNode,
4756
} from "../_namespaces/ts.codefix";
4857

4958
const addMissingParamFixId = "addMissingParam";
@@ -65,7 +74,7 @@ registerCodeFix({
6574
actions,
6675
createCodeFixAction(
6776
addMissingParamFixId,
68-
textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declarations, newParameters)),
77+
textChanges.ChangeTracker.with(context, t => doChange(t, context.program, context.preferences, context.host, declarations, newParameters)),
6978
[length(newParameters) > 1 ? Diagnostics.Add_missing_parameters_to_0 : Diagnostics.Add_missing_parameter_to_0, name],
7079
addMissingParamFixId,
7180
Diagnostics.Add_all_missing_parameters,
@@ -78,7 +87,7 @@ registerCodeFix({
7887
actions,
7988
createCodeFixAction(
8089
addOptionalParamFixId,
81-
textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declarations, newOptionalParameters)),
90+
textChanges.ChangeTracker.with(context, t => doChange(t, context.program, context.preferences, context.host, declarations, newOptionalParameters)),
8291
[length(newOptionalParameters) > 1 ? Diagnostics.Add_optional_parameters_to_0 : Diagnostics.Add_optional_parameter_to_0, name],
8392
addOptionalParamFixId,
8493
Diagnostics.Add_all_optional_parameters,
@@ -94,10 +103,10 @@ registerCodeFix({
94103
if (info) {
95104
const { declarations, newParameters, newOptionalParameters } = info;
96105
if (context.fixId === addMissingParamFixId) {
97-
doChange(changes, context.sourceFile, declarations, newParameters);
106+
doChange(changes, context.program, context.preferences, context.host, declarations, newParameters);
98107
}
99108
if (context.fixId === addOptionalParamFixId) {
100-
doChange(changes, context.sourceFile, declarations, newOptionalParameters);
109+
doChange(changes, context.program, context.preferences, context.host, declarations, newOptionalParameters);
101110
}
102111
}
103112
}),
@@ -218,17 +227,22 @@ function typeToTypeNode(checker: TypeChecker, type: Type, enclosingDeclaration:
218227

219228
function doChange(
220229
changes: textChanges.ChangeTracker,
221-
sourceFile: SourceFile,
230+
program: Program,
231+
preferences: UserPreferences,
232+
host: LanguageServiceHost,
222233
declarations: ConvertibleSignatureDeclaration[],
223234
newParameters: ParameterInfo[],
224235
) {
236+
const scriptTarget = getEmitScriptTarget(program.getCompilerOptions());
225237
forEach(declarations, declaration => {
238+
const sourceFile = getSourceFileOfNode(declaration);
239+
const importAdder = createImportAdder(sourceFile, program, preferences, host);
226240
if (length(declaration.parameters)) {
227241
changes.replaceNodeRangeWithNodes(
228242
sourceFile,
229243
first(declaration.parameters),
230244
last(declaration.parameters),
231-
updateParameters(declaration, newParameters),
245+
updateParameters(importAdder, scriptTarget, declaration, newParameters),
232246
{
233247
joiner: ", ",
234248
indentation: 0,
@@ -238,7 +252,7 @@ function doChange(
238252
);
239253
}
240254
else {
241-
forEach(updateParameters(declaration, newParameters), (parameter, index) => {
255+
forEach(updateParameters(importAdder, scriptTarget, declaration, newParameters), (parameter, index) => {
242256
if (length(declaration.parameters) === 0 && index === 0) {
243257
changes.insertNodeAt(sourceFile, declaration.parameters.end, parameter);
244258
}
@@ -247,6 +261,7 @@ function doChange(
247261
}
248262
});
249263
}
264+
importAdder.writeFixes(changes);
250265
});
251266
}
252267

@@ -262,7 +277,12 @@ function isConvertibleSignatureDeclaration(node: Node): node is ConvertibleSigna
262277
}
263278
}
264279

265-
function updateParameters(node: ConvertibleSignatureDeclaration, newParameters: readonly ParameterInfo[]) {
280+
function updateParameters(
281+
importAdder: ImportAdder,
282+
scriptTarget: ScriptTarget,
283+
node: ConvertibleSignatureDeclaration,
284+
newParameters: readonly ParameterInfo[],
285+
) {
266286
const parameters = map(node.parameters, p =>
267287
factory.createParameterDeclaration(
268288
p.modifiers,
@@ -283,7 +303,7 @@ function updateParameters(node: ConvertibleSignatureDeclaration, newParameters:
283303
declaration.dotDotDotToken,
284304
declaration.name,
285305
prev && prev.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : declaration.questionToken,
286-
declaration.type,
306+
getParameterType(importAdder, declaration.type, scriptTarget),
287307
declaration.initializer,
288308
),
289309
);
@@ -325,3 +345,12 @@ function createParameter(name: string, type: TypeNode, questionToken: QuestionTo
325345
function isOptionalPos(declarations: ConvertibleSignatureDeclaration[], pos: number) {
326346
return length(declarations) && some(declarations, d => pos < length(d.parameters) && !!d.parameters[pos] && d.parameters[pos].questionToken === undefined);
327347
}
348+
349+
function getParameterType(importAdder: ImportAdder, typeNode: TypeNode | undefined, scriptTarget: ScriptTarget) {
350+
const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget);
351+
if (importableReference) {
352+
importSymbols(importAdder, importableReference.symbols);
353+
return importableReference.typeNode;
354+
}
355+
return typeNode;
356+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @filename: /a.ts
4+
//// export class A {}
5+
6+
// @filename: /b.ts
7+
//// export function f(a: any) {}
8+
9+
// @filename: /c.ts
10+
//// import { A } from './a';
11+
//// import { f } from './b';
12+
////
13+
//// f({}, new A());
14+
15+
goTo.file("/c.ts");
16+
17+
verify.codeFix({
18+
description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"],
19+
index: 0,
20+
newFileContent: {
21+
"/b.ts":
22+
`import { A } from "./a";
23+
24+
export function f(a: any, p0: A) {}`,
25+
},
26+
});

0 commit comments

Comments
 (0)