mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
feat(11378): check param names in JSDoc (#47257)
This commit is contained in:
parent
954ce5b278
commit
b456702755
@ -34472,6 +34472,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
checkTypeParameters(getEffectiveTypeParameterDeclarations(node));
|
||||
checkUnmatchedJSDocParameters(node);
|
||||
|
||||
forEach(node.parameters, checkParameter);
|
||||
|
||||
@ -36235,40 +36236,7 @@ namespace ts {
|
||||
|
||||
function checkJSDocParameterTag(node: JSDocParameterTag) {
|
||||
checkSourceElement(node.typeExpression);
|
||||
if (!getParameterSymbolFromJSDoc(node)) {
|
||||
const decl = getHostSignatureFromJSDoc(node);
|
||||
// don't issue an error for invalid hosts -- just functions --
|
||||
// and give a better error message when the host function mentions `arguments`
|
||||
// but the tag doesn't have an array type
|
||||
if (decl) {
|
||||
const i = getJSDocTags(decl).filter(isJSDocParameterTag).indexOf(node);
|
||||
if (i > -1 && i < decl.parameters.length && isBindingPattern(decl.parameters[i].name)) {
|
||||
return;
|
||||
}
|
||||
if (!containsArgumentsReference(decl)) {
|
||||
if (isQualifiedName(node.name)) {
|
||||
error(node.name,
|
||||
Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1,
|
||||
entityNameToString(node.name),
|
||||
entityNameToString(node.name.left));
|
||||
}
|
||||
else {
|
||||
error(node.name,
|
||||
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
|
||||
idText(node.name));
|
||||
}
|
||||
}
|
||||
else if (findLast(getJSDocTags(decl), isJSDocParameterTag) === node &&
|
||||
node.typeExpression && node.typeExpression.type &&
|
||||
!isArrayType(getTypeFromTypeNode(node.typeExpression.type))) {
|
||||
error(node.name,
|
||||
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type,
|
||||
idText(node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkJSDocPropertyTag(node: JSDocPropertyTag) {
|
||||
checkSourceElement(node.typeExpression);
|
||||
}
|
||||
@ -38564,6 +38532,45 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkUnmatchedJSDocParameters(node: SignatureDeclaration) {
|
||||
const jsdocParameters = filter(getJSDocTags(node), isJSDocParameterTag);
|
||||
if (!length(jsdocParameters)) return;
|
||||
|
||||
const isJs = isInJSFile(node);
|
||||
const parameters = new Set<__String>();
|
||||
const excludedParameters = new Set<number>();
|
||||
forEach(node.parameters, ({ name }, index) => {
|
||||
if (isIdentifier(name)) {
|
||||
parameters.add(name.escapedText);
|
||||
}
|
||||
if (isBindingPattern(name)) {
|
||||
excludedParameters.add(index);
|
||||
}
|
||||
});
|
||||
|
||||
const containsArguments = containsArgumentsReference(node);
|
||||
if (containsArguments) {
|
||||
const lastJSDocParam = lastOrUndefined(jsdocParameters);
|
||||
if (lastJSDocParam && isIdentifier(lastJSDocParam.name) && lastJSDocParam.typeExpression &&
|
||||
lastJSDocParam.typeExpression.type && !parameters.has(lastJSDocParam.name.escapedText) && !isArrayType(getTypeFromTypeNode(lastJSDocParam.typeExpression.type))) {
|
||||
errorOrSuggestion(isJs, lastJSDocParam.name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type, idText(lastJSDocParam.name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
forEach(jsdocParameters, ({ name }, index) => {
|
||||
if (excludedParameters.has(index) || isIdentifier(name) && parameters.has(name.escapedText)) {
|
||||
return;
|
||||
}
|
||||
if (isQualifiedName(name)) {
|
||||
errorOrSuggestion(isJs, name, Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, entityNameToString(name), entityNameToString(name.left));
|
||||
}
|
||||
else {
|
||||
errorOrSuggestion(isJs, name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, idText(name));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check each type parameter and check that type parameters have no duplicate type parameter declarations
|
||||
*/
|
||||
|
||||
@ -7135,6 +7135,18 @@
|
||||
"category": "Message",
|
||||
"code": 95170
|
||||
},
|
||||
"Delete unused '@param' tag '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95171
|
||||
},
|
||||
"Delete all unused '@param' tags": {
|
||||
"category": "Message",
|
||||
"code": 95172
|
||||
},
|
||||
"Rename '@param' tag name '{0}' to '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 95173
|
||||
},
|
||||
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
|
||||
104
src/services/codefixes/fixUnmatchedParameter.ts
Normal file
104
src/services/codefixes/fixUnmatchedParameter.ts
Normal file
@ -0,0 +1,104 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const deleteUnmatchedParameter = "deleteUnmatchedParameter";
|
||||
const renameUnmatchedParameter = "renameUnmatchedParameter";
|
||||
|
||||
const errorCodes = [
|
||||
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name.code,
|
||||
];
|
||||
|
||||
registerCodeFix({
|
||||
fixIds: [deleteUnmatchedParameter, renameUnmatchedParameter],
|
||||
errorCodes,
|
||||
getCodeActions: function getCodeActionsToFixUnmatchedParameter(context) {
|
||||
const { sourceFile, span } = context;
|
||||
const actions: CodeFixAction[] = [];
|
||||
const info = getInfo(sourceFile, span.start);
|
||||
if (info) {
|
||||
append(actions, getDeleteAction(context, info));
|
||||
append(actions, getRenameAction(context, info));
|
||||
return actions;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
getAllCodeActions: function getAllCodeActionsToFixUnmatchedParameter(context) {
|
||||
const tagsToSignature = new Map<SignatureDeclaration, JSDocTag[]>();
|
||||
return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => {
|
||||
eachDiagnostic(context, errorCodes, ({ file, start }) => {
|
||||
const info = getInfo(file, start);
|
||||
if (info) {
|
||||
tagsToSignature.set(info.signature, append(tagsToSignature.get(info.signature), info.jsDocParameterTag));
|
||||
}
|
||||
});
|
||||
|
||||
tagsToSignature.forEach((tags, signature) => {
|
||||
if (context.fixId === deleteUnmatchedParameter) {
|
||||
const tagsSet = new Set(tags);
|
||||
changes.filterJSDocTags(signature.getSourceFile(), signature, t => !tagsSet.has(t));
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
function getDeleteAction(context: CodeFixContext, { name, signature, jsDocParameterTag }: Info) {
|
||||
const changes = textChanges.ChangeTracker.with(context, changeTracker =>
|
||||
changeTracker.filterJSDocTags(context.sourceFile, signature, t => t !== jsDocParameterTag));
|
||||
return createCodeFixAction(
|
||||
deleteUnmatchedParameter,
|
||||
changes,
|
||||
[Diagnostics.Delete_unused_param_tag_0, name.getText(context.sourceFile)],
|
||||
deleteUnmatchedParameter,
|
||||
Diagnostics.Delete_all_unused_param_tags
|
||||
);
|
||||
}
|
||||
|
||||
function getRenameAction(context: CodeFixContext, { name, signature, jsDocParameterTag }: Info) {
|
||||
if (!length(signature.parameters)) return undefined;
|
||||
|
||||
const sourceFile = context.sourceFile;
|
||||
const tags = getJSDocTags(signature);
|
||||
const names = new Set<__String>();
|
||||
for (const tag of tags) {
|
||||
if (isJSDocParameterTag(tag) && isIdentifier(tag.name)) {
|
||||
names.add(tag.name.escapedText);
|
||||
}
|
||||
}
|
||||
// @todo - match to all available names instead to the first parameter name
|
||||
// @see /codeFixRenameUnmatchedParameter3.ts
|
||||
const parameterName = firstDefined(signature.parameters, p =>
|
||||
isIdentifier(p.name) && !names.has(p.name.escapedText) ? p.name.getText(sourceFile) : undefined);
|
||||
if (parameterName === undefined) return undefined;
|
||||
|
||||
const newJSDocParameterTag = factory.updateJSDocParameterTag(
|
||||
jsDocParameterTag,
|
||||
jsDocParameterTag.tagName,
|
||||
factory.createIdentifier(parameterName),
|
||||
jsDocParameterTag.isBracketed,
|
||||
jsDocParameterTag.typeExpression,
|
||||
jsDocParameterTag.isNameFirst,
|
||||
jsDocParameterTag.comment
|
||||
);
|
||||
const changes = textChanges.ChangeTracker.with(context, changeTracker =>
|
||||
changeTracker.replaceJSDocComment(sourceFile, signature, map(tags, t => t === jsDocParameterTag ? newJSDocParameterTag : t)));
|
||||
return createCodeFixActionWithoutFixAll(renameUnmatchedParameter, changes, [Diagnostics.Rename_param_tag_name_0_to_1, name.getText(sourceFile), parameterName]);
|
||||
}
|
||||
|
||||
interface Info {
|
||||
readonly signature: SignatureDeclaration;
|
||||
readonly jsDocParameterTag: JSDocParameterTag;
|
||||
readonly name: Identifier;
|
||||
}
|
||||
|
||||
function getInfo(sourceFile: SourceFile, pos: number): Info | undefined {
|
||||
const token = getTokenAtPosition(sourceFile, pos);
|
||||
if (token.parent && isJSDocParameterTag(token.parent) && isIdentifier(token.parent.name)) {
|
||||
const jsDocParameterTag = token.parent;
|
||||
const signature = getHostSignatureFromJSDoc(jsDocParameterTag);
|
||||
if (signature) {
|
||||
return { signature, name: token.parent.name, jsDocParameterTag };
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@ -495,29 +495,30 @@ namespace ts.textChanges {
|
||||
this.insertNodeAt(sourceFile, fnStart, tag, { preserveLeadingWhitespace: false, suffix: this.newLineCharacter + indent });
|
||||
}
|
||||
|
||||
private createJSDocText(sourceFile: SourceFile, node: HasJSDoc) {
|
||||
const comments = flatMap(node.jsDoc, jsDoc =>
|
||||
isString(jsDoc.comment) ? factory.createJSDocText(jsDoc.comment) : jsDoc.comment) as JSDocComment[];
|
||||
const jsDoc = singleOrUndefined(node.jsDoc);
|
||||
return jsDoc && positionsAreOnSameLine(jsDoc.pos, jsDoc.end, sourceFile) && length(comments) === 0 ? undefined :
|
||||
factory.createNodeArray(intersperse(comments, factory.createJSDocText("\n")));
|
||||
}
|
||||
|
||||
public replaceJSDocComment(sourceFile: SourceFile, node: HasJSDoc, tags: readonly JSDocTag[]) {
|
||||
this.insertJsdocCommentBefore(sourceFile, updateJSDocHost(node), factory.createJSDocComment(this.createJSDocText(sourceFile, node), factory.createNodeArray(tags)));
|
||||
}
|
||||
|
||||
public addJSDocTags(sourceFile: SourceFile, parent: HasJSDoc, newTags: readonly JSDocTag[]): void {
|
||||
const comments = flatMap(parent.jsDoc, j => typeof j.comment === "string" ? factory.createJSDocText(j.comment) : j.comment) as JSDocComment[];
|
||||
const oldTags = flatMapToMutable(parent.jsDoc, j => j.tags);
|
||||
const unmergedNewTags = newTags.filter(newTag => !oldTags.some((tag, i) => {
|
||||
const merged = tryMergeJsdocTags(tag, newTag);
|
||||
if (merged) oldTags[i] = merged;
|
||||
return !!merged;
|
||||
}));
|
||||
const tags = [...oldTags, ...unmergedNewTags];
|
||||
const jsDoc = singleOrUndefined(parent.jsDoc);
|
||||
const comment = jsDoc && positionsAreOnSameLine(jsDoc.pos, jsDoc.end, sourceFile) && !length(comments) ? undefined :
|
||||
factory.createNodeArray(intersperse(comments, factory.createJSDocText("\n")));
|
||||
const tag = factory.createJSDocComment(comment, factory.createNodeArray(tags));
|
||||
const host = updateJSDocHost(parent);
|
||||
this.insertJsdocCommentBefore(sourceFile, host, tag);
|
||||
this.replaceJSDocComment(sourceFile, parent, [...oldTags, ...unmergedNewTags]);
|
||||
}
|
||||
|
||||
public filterJSDocTags(sourceFile: SourceFile, parent: HasJSDoc, predicate: (tag: JSDocTag) => boolean): void {
|
||||
const comments = flatMap(parent.jsDoc, j => typeof j.comment === "string" ? factory.createJSDocText(j.comment) : j.comment) as JSDocComment[];
|
||||
const oldTags = flatMapToMutable(parent.jsDoc, j => j.tags);
|
||||
const tag = factory.createJSDocComment(factory.createNodeArray(intersperse(comments, factory.createJSDocText("\n"))), factory.createNodeArray([...(filter(oldTags, predicate) || emptyArray)]));
|
||||
const host = updateJSDocHost(parent);
|
||||
this.insertJsdocCommentBefore(sourceFile, host, tag);
|
||||
this.replaceJSDocComment(sourceFile, parent, filter(flatMapToMutable(parent.jsDoc, j => j.tags), predicate));
|
||||
}
|
||||
|
||||
public replaceRangeWithText(sourceFile: SourceFile, range: TextRange, text: string): void {
|
||||
|
||||
@ -87,6 +87,7 @@
|
||||
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
|
||||
"codefixes/fixForgottenThisPropertyAccess.ts",
|
||||
"codefixes/fixInvalidJsxCharacters.ts",
|
||||
"codefixes/fixUnmatchedParameter.ts",
|
||||
"codefixes/fixUnusedIdentifier.ts",
|
||||
"codefixes/fixUnreachableCode.ts",
|
||||
"codefixes/fixUnusedLabel.ts",
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
tests/cases/conformance/jsdoc/0.js(14,20): error TS8024: JSDoc '@param' tag has name 's', but there is no parameter with that name.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/0.js (1 errors) ====
|
||||
// @ts-check
|
||||
/**
|
||||
* @param {number=} n
|
||||
* @param {string} [s]
|
||||
*/
|
||||
var x = function foo(n, s) {}
|
||||
var y;
|
||||
/**
|
||||
* @param {boolean!} b
|
||||
*/
|
||||
y = function bar(b) {}
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
~
|
||||
!!! error TS8024: JSDoc '@param' tag has name 's', but there is no parameter with that name.
|
||||
*/
|
||||
var one = function (s) { }, two = function (untyped) { };
|
||||
|
||||
23
tests/cases/fourslash/codeFixDeleteUnmatchedParameter1.ts
Normal file
23
tests/cases/fourslash/codeFixDeleteUnmatchedParameter1.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: a.ts
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function foo() {}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'a'" },
|
||||
{ description: "Delete unused '@param' tag 'b'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "a"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo() {}`,
|
||||
});
|
||||
26
tests/cases/fourslash/codeFixDeleteUnmatchedParameter2.ts
Normal file
26
tests/cases/fourslash/codeFixDeleteUnmatchedParameter2.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: a.ts
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// */
|
||||
////function foo(a: number) {
|
||||
//// a;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'b'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "b"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} a
|
||||
*/
|
||||
function foo(a: number) {
|
||||
a;
|
||||
}`
|
||||
});
|
||||
30
tests/cases/fourslash/codeFixDeleteUnmatchedParameter3.ts
Normal file
30
tests/cases/fourslash/codeFixDeleteUnmatchedParameter3.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: a.ts
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// * @param {number} c
|
||||
//// */
|
||||
////function foo(a: number, c: number) {
|
||||
//// a;
|
||||
//// c;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'b'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "b"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} a
|
||||
* @param {number} c
|
||||
*/
|
||||
function foo(a: number, c: number) {
|
||||
a;
|
||||
c;
|
||||
}`
|
||||
});
|
||||
19
tests/cases/fourslash/codeFixDeleteUnmatchedParameter4.ts
Normal file
19
tests/cases/fourslash/codeFixDeleteUnmatchedParameter4.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: a.ts
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// */
|
||||
////function foo() {}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'a'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "a"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/** */
|
||||
function foo() {}`
|
||||
});
|
||||
27
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS1.ts
Normal file
27
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS1.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function foo() {}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'a'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
{ description: "Delete unused '@param' tag 'b'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "a"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo() {}`,
|
||||
});
|
||||
29
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS2.ts
Normal file
29
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS2.ts
Normal file
@ -0,0 +1,29 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// */
|
||||
////function foo(a) {
|
||||
//// a;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'b'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "b"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} a
|
||||
*/
|
||||
function foo(a) {
|
||||
a;
|
||||
}`
|
||||
});
|
||||
33
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS3.ts
Normal file
33
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS3.ts
Normal file
@ -0,0 +1,33 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// * @param {number} c
|
||||
//// */
|
||||
////function foo(a, c) {
|
||||
//// a;
|
||||
//// c;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'b'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "b"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} a
|
||||
* @param {number} c
|
||||
*/
|
||||
function foo(a, c) {
|
||||
a;
|
||||
c;
|
||||
}`
|
||||
});
|
||||
22
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS4.ts
Normal file
22
tests/cases/fourslash/codeFixDeleteUnmatchedParameterJS4.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// */
|
||||
////function foo() {}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'a'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Delete_unused_param_tag_0.message, "a"],
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`/** */
|
||||
function foo() {}`
|
||||
});
|
||||
51
tests/cases/fourslash/codeFixDeleteUnmatchedParameter_all.ts
Normal file
51
tests/cases/fourslash/codeFixDeleteUnmatchedParameter_all.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: /a.ts
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function f1() {}
|
||||
////
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// */
|
||||
////function f2(a: number) {
|
||||
//// a;
|
||||
////}
|
||||
////
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// * @param {number} c
|
||||
//// */
|
||||
////function f3(a: number, c: number) {
|
||||
//// a;
|
||||
//// c;
|
||||
////}
|
||||
|
||||
goTo.file("/a.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "deleteUnmatchedParameter",
|
||||
fixAllDescription: ts.Diagnostics.Delete_all_unused_param_tags.message,
|
||||
newFileContent:
|
||||
`/** */
|
||||
function f1() {}
|
||||
|
||||
/**
|
||||
* @param {number} a
|
||||
*/
|
||||
function f2(a: number) {
|
||||
a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} a
|
||||
* @param {number} c
|
||||
*/
|
||||
function f3(a: number, c: number) {
|
||||
a;
|
||||
c;
|
||||
}`,
|
||||
});
|
||||
@ -0,0 +1,53 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function f1() {}
|
||||
////
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// */
|
||||
////function f2(a) {
|
||||
//// a;
|
||||
////}
|
||||
////
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// * @param {number} c
|
||||
//// */
|
||||
////function f3(a, c) {
|
||||
//// a;
|
||||
//// c;
|
||||
////}
|
||||
|
||||
goTo.file("/a.js");
|
||||
verify.codeFixAll({
|
||||
fixId: "deleteUnmatchedParameter",
|
||||
fixAllDescription: ts.Diagnostics.Delete_all_unused_param_tags.message,
|
||||
newFileContent:
|
||||
`/** */
|
||||
function f1() {}
|
||||
|
||||
/**
|
||||
* @param {number} a
|
||||
*/
|
||||
function f2(a) {
|
||||
a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} a
|
||||
* @param {number} c
|
||||
*/
|
||||
function f3(a, c) {
|
||||
a;
|
||||
c;
|
||||
}`,
|
||||
});
|
||||
30
tests/cases/fourslash/codeFixRenameUnmatchedParameter1.ts
Normal file
30
tests/cases/fourslash/codeFixRenameUnmatchedParameter1.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: a.ts
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {number} c
|
||||
//// */
|
||||
////function foo(a: number, b: string) {
|
||||
//// a;
|
||||
//// b;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'c'" },
|
||||
{ description: "Rename '@param' tag name 'c' to 'b'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "c", "b"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a: number, b: string) {
|
||||
a;
|
||||
b;
|
||||
}`
|
||||
});
|
||||
34
tests/cases/fourslash/codeFixRenameUnmatchedParameter2.ts
Normal file
34
tests/cases/fourslash/codeFixRenameUnmatchedParameter2.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: a.ts
|
||||
/////**
|
||||
//// * @param {number} d
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function foo(a: number, b: string, c: string) {
|
||||
//// a;
|
||||
//// b;
|
||||
//// c;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'd'" },
|
||||
{ description: "Rename '@param' tag name 'd' to 'c'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "d", "c"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} c
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a: number, b: string, c: string) {
|
||||
a;
|
||||
b;
|
||||
c;
|
||||
}`
|
||||
});
|
||||
64
tests/cases/fourslash/codeFixRenameUnmatchedParameter3.ts
Normal file
64
tests/cases/fourslash/codeFixRenameUnmatchedParameter3.ts
Normal file
@ -0,0 +1,64 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @filename: a.ts
|
||||
/////**
|
||||
//// * @param {number} notDefined1
|
||||
//// * @param {number} notDefined2
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function foo(a: number, b: string, typo1: string, typo2: string) {
|
||||
//// a;
|
||||
//// b;
|
||||
//// typo1;
|
||||
//// typo2;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'notDefined1'" },
|
||||
{ description: "Rename '@param' tag name 'notDefined1' to 'typo1'" },
|
||||
{ description: "Delete unused '@param' tag 'notDefined2'" },
|
||||
{ description: "Rename '@param' tag name 'notDefined2' to 'typo1'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "notDefined1", "typo1"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} typo1
|
||||
* @param {number} notDefined2
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a: number, b: string, typo1: string, typo2: string) {
|
||||
a;
|
||||
b;
|
||||
typo1;
|
||||
typo2;
|
||||
}`,
|
||||
applyChanges: true
|
||||
});
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'notDefined2'" },
|
||||
{ description: "Rename '@param' tag name 'notDefined2' to 'typo2'" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "notDefined2", "typo2"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} typo1
|
||||
* @param {number} typo2
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a: number, b: string, typo1: string, typo2: string) {
|
||||
a;
|
||||
b;
|
||||
typo1;
|
||||
typo2;
|
||||
}`,
|
||||
});
|
||||
34
tests/cases/fourslash/codeFixRenameUnmatchedParameterJS1.ts
Normal file
34
tests/cases/fourslash/codeFixRenameUnmatchedParameterJS1.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} a
|
||||
//// * @param {number} c
|
||||
//// */
|
||||
////function foo(a, b) {
|
||||
//// a;
|
||||
//// b;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'c'" },
|
||||
{ description: "Rename '@param' tag name 'c' to 'b'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
{ description: "Infer parameter types from usage" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "c", "b"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a, b) {
|
||||
a;
|
||||
b;
|
||||
}`
|
||||
});
|
||||
38
tests/cases/fourslash/codeFixRenameUnmatchedParameterJS2.ts
Normal file
38
tests/cases/fourslash/codeFixRenameUnmatchedParameterJS2.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} d
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function foo(a, b, c) {
|
||||
//// a;
|
||||
//// b;
|
||||
//// c;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'd'" },
|
||||
{ description: "Rename '@param' tag name 'd' to 'c'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
{ description: "Infer parameter types from usage" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "d", "c"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} c
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a, b, c) {
|
||||
a;
|
||||
b;
|
||||
c;
|
||||
}`
|
||||
});
|
||||
72
tests/cases/fourslash/codeFixRenameUnmatchedParameterJS3.ts
Normal file
72
tests/cases/fourslash/codeFixRenameUnmatchedParameterJS3.ts
Normal file
@ -0,0 +1,72 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @filename: /a.js
|
||||
/////**
|
||||
//// * @param {number} notDefined1
|
||||
//// * @param {number} notDefined2
|
||||
//// * @param {number} a
|
||||
//// * @param {number} b
|
||||
//// */
|
||||
////function foo(a, b, typo1, typo2) {
|
||||
//// a;
|
||||
//// b;
|
||||
//// typo1;
|
||||
//// typo2;
|
||||
////}
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'notDefined1'" },
|
||||
{ description: "Rename '@param' tag name 'notDefined1' to 'typo1'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
{ description: "Delete unused '@param' tag 'notDefined2'" },
|
||||
{ description: "Rename '@param' tag name 'notDefined2' to 'typo1'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
{ description: "Infer parameter types from usage" },
|
||||
{ description: "Infer parameter types from usage" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "notDefined1", "typo1"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} typo1
|
||||
* @param {number} notDefined2
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a, b, typo1, typo2) {
|
||||
a;
|
||||
b;
|
||||
typo1;
|
||||
typo2;
|
||||
}`,
|
||||
applyChanges: true
|
||||
});
|
||||
|
||||
verify.codeFixAvailable([
|
||||
{ description: "Delete unused '@param' tag 'notDefined2'" },
|
||||
{ description: "Rename '@param' tag name 'notDefined2' to 'typo2'" },
|
||||
{ description: "Disable checking for this file" },
|
||||
{ description: "Infer parameter types from usage" },
|
||||
]);
|
||||
|
||||
verify.codeFix({
|
||||
description: [ts.Diagnostics.Rename_param_tag_name_0_to_1.message, "notDefined2", "typo2"],
|
||||
index: 1,
|
||||
newFileContent:
|
||||
`/**
|
||||
* @param {number} typo1
|
||||
* @param {number} typo2
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
function foo(a, b, typo1, typo2) {
|
||||
a;
|
||||
b;
|
||||
typo1;
|
||||
typo2;
|
||||
}`,
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user