Skip to content

Commit

Permalink
fix(58360): Cheese being inserted on TypeScript Quick Fix (#58365)
Browse files Browse the repository at this point in the history
  • Loading branch information
a-tarasyuk committed Apr 29, 2024
1 parent c763c27 commit dc316af
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 9 deletions.
47 changes: 38 additions & 9 deletions src/services/codefixes/fixAddMissingParam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import {
FunctionDeclaration,
FunctionExpression,
FunctionLikeDeclaration,
getEmitScriptTarget,
getNameOfAccessExpression,
getNameOfDeclaration,
getSourceFileOfNode,
getTokenAtPosition,
isAccessExpression,
isCallExpression,
Expand All @@ -22,6 +24,7 @@ import {
isPropertyDeclaration,
isSourceFileFromLibrary,
isVariableDeclaration,
LanguageServiceHost,
last,
lastOrUndefined,
length,
Expand All @@ -32,18 +35,24 @@ import {
ParameterDeclaration,
Program,
QuestionToken,
ScriptTarget,
some,
SourceFile,
SyntaxKind,
textChanges,
Type,
TypeChecker,
TypeNode,
UserPreferences,
} from "../_namespaces/ts";
import {
codeFixAll,
createCodeFixAction,
createImportAdder,
ImportAdder,
importSymbols,
registerCodeFix,
tryGetAutoImportableReferenceFromTypeNode,
} from "../_namespaces/ts.codefix";

const addMissingParamFixId = "addMissingParam";
Expand All @@ -65,7 +74,7 @@ registerCodeFix({
actions,
createCodeFixAction(
addMissingParamFixId,
textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declarations, newParameters)),
textChanges.ChangeTracker.with(context, t => doChange(t, context.program, context.preferences, context.host, declarations, newParameters)),
[length(newParameters) > 1 ? Diagnostics.Add_missing_parameters_to_0 : Diagnostics.Add_missing_parameter_to_0, name],
addMissingParamFixId,
Diagnostics.Add_all_missing_parameters,
Expand All @@ -78,7 +87,7 @@ registerCodeFix({
actions,
createCodeFixAction(
addOptionalParamFixId,
textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declarations, newOptionalParameters)),
textChanges.ChangeTracker.with(context, t => doChange(t, context.program, context.preferences, context.host, declarations, newOptionalParameters)),
[length(newOptionalParameters) > 1 ? Diagnostics.Add_optional_parameters_to_0 : Diagnostics.Add_optional_parameter_to_0, name],
addOptionalParamFixId,
Diagnostics.Add_all_optional_parameters,
Expand All @@ -94,10 +103,10 @@ registerCodeFix({
if (info) {
const { declarations, newParameters, newOptionalParameters } = info;
if (context.fixId === addMissingParamFixId) {
doChange(changes, context.sourceFile, declarations, newParameters);
doChange(changes, context.program, context.preferences, context.host, declarations, newParameters);
}
if (context.fixId === addOptionalParamFixId) {
doChange(changes, context.sourceFile, declarations, newOptionalParameters);
doChange(changes, context.program, context.preferences, context.host, declarations, newOptionalParameters);
}
}
}),
Expand Down Expand Up @@ -218,17 +227,22 @@ function typeToTypeNode(checker: TypeChecker, type: Type, enclosingDeclaration:

function doChange(
changes: textChanges.ChangeTracker,
sourceFile: SourceFile,
program: Program,
preferences: UserPreferences,
host: LanguageServiceHost,
declarations: ConvertibleSignatureDeclaration[],
newParameters: ParameterInfo[],
) {
const scriptTarget = getEmitScriptTarget(program.getCompilerOptions());
forEach(declarations, declaration => {
const sourceFile = getSourceFileOfNode(declaration);
const importAdder = createImportAdder(sourceFile, program, preferences, host);
if (length(declaration.parameters)) {
changes.replaceNodeRangeWithNodes(
sourceFile,
first(declaration.parameters),
last(declaration.parameters),
updateParameters(declaration, newParameters),
updateParameters(importAdder, scriptTarget, declaration, newParameters),
{
joiner: ", ",
indentation: 0,
Expand All @@ -238,7 +252,7 @@ function doChange(
);
}
else {
forEach(updateParameters(declaration, newParameters), (parameter, index) => {
forEach(updateParameters(importAdder, scriptTarget, declaration, newParameters), (parameter, index) => {
if (length(declaration.parameters) === 0 && index === 0) {
changes.insertNodeAt(sourceFile, declaration.parameters.end, parameter);
}
Expand All @@ -247,6 +261,7 @@ function doChange(
}
});
}
importAdder.writeFixes(changes);
});
}

Expand All @@ -262,7 +277,12 @@ function isConvertibleSignatureDeclaration(node: Node): node is ConvertibleSigna
}
}

function updateParameters(node: ConvertibleSignatureDeclaration, newParameters: readonly ParameterInfo[]) {
function updateParameters(
importAdder: ImportAdder,
scriptTarget: ScriptTarget,
node: ConvertibleSignatureDeclaration,
newParameters: readonly ParameterInfo[],
) {
const parameters = map(node.parameters, p =>
factory.createParameterDeclaration(
p.modifiers,
Expand All @@ -283,7 +303,7 @@ function updateParameters(node: ConvertibleSignatureDeclaration, newParameters:
declaration.dotDotDotToken,
declaration.name,
prev && prev.questionToken ? factory.createToken(SyntaxKind.QuestionToken) : declaration.questionToken,
declaration.type,
getParameterType(importAdder, declaration.type, scriptTarget),
declaration.initializer,
),
);
Expand Down Expand Up @@ -325,3 +345,12 @@ function createParameter(name: string, type: TypeNode, questionToken: QuestionTo
function isOptionalPos(declarations: ConvertibleSignatureDeclaration[], pos: number) {
return length(declarations) && some(declarations, d => pos < length(d.parameters) && !!d.parameters[pos] && d.parameters[pos].questionToken === undefined);
}

function getParameterType(importAdder: ImportAdder, typeNode: TypeNode | undefined, scriptTarget: ScriptTarget) {
const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget);
if (importableReference) {
importSymbols(importAdder, importableReference.symbols);
return importableReference.typeNode;
}
return typeNode;
}
26 changes: 26 additions & 0 deletions tests/cases/fourslash/codeFixAddMissingParam17.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/// <reference path="fourslash.ts" />

// @filename: /a.ts
//// export class A {}

// @filename: /b.ts
//// export function f(a: any) {}

// @filename: /c.ts
//// import { A } from './a';
//// import { f } from './b';
////
//// f({}, new A());

goTo.file("/c.ts");

verify.codeFix({
description: [ts.Diagnostics.Add_missing_parameter_to_0.message, "f"],
index: 0,
newFileContent: {
"/b.ts":
`import { A } from "./a";
export function f(a: any, p0: A) {}`,
},
});

0 comments on commit dc316af

Please sign in to comment.