Skip to content

No error on unmatchable @param tags #22510

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 14, 2018
Merged

Conversation

sandersn
Copy link
Member

Such as when the initializer is not a function, or when the function mentions arguments in its body.

Fixes #22410
Fixes #22411

This will need to be ported to 2.8 as well.

Such as when the initializer is not a function, or when the function
mentions `arguments` in its body.
@sandersn sandersn requested review from mhegazy and a user March 13, 2018 17:45
@sandersn sandersn changed the title No errr on unmatchable @param tags No error on unmatchable @param tags Mar 13, 2018
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @strict: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this matter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. It was part of my template when generating a bunch of these similar JSDoc bugs. I removed it.

@@ -21447,7 +21447,8 @@ namespace ts {

function checkJSDocParameterTag(node: JSDocParameterTag) {
checkSourceElement(node.typeExpression);
if (!getParameterSymbolFromJSDoc(node)) {
const decl = getHostSignatureFromJSDoc(node);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getHostSignatureFromJSDoc looks expensive and we won't use it if the param has a symbol; better to put it in an inner if.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good idea. It's also called twice -- once in getParameterSymbolFromJSDoc -- but I don't know that it's worthwhile to fix that.

// @Filename: a.js

/**
* @param {string} first
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case I'm not so sure about supporting since people will think they're getting typing, when we just throw the type definition away without telling them and accept any. Instead we could add a better message telling them to use a rest parameter instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rest parameters don't exist in ES5, so the error would only apply to ES2015 and later. And we don't usually know whether a .js file targets ES2015 or later.

As for throwing away typing, I don't think there's much we can do -- maybe a noImplicitAny error instead?

I think it would be easier to error (to info-error?) whenever there's a reference to arguments. That error would be a lot easier to write, and would apply to both ES2015+ and TS, and should come with an associated quick fix. I'll open a separate issue for that.

Copy link

@ghost ghost Mar 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we require the user to place a dummy-parameter and type it as a rest parameter:

/** @param {...string} x */
function f(x) {
    return arguments[0];
}
f(1); // error, 1 is not a string

We could make a codefix to convert @param {string} first to @param {...string} args and add the dummy parameter -- we could also stop requiring the dumy parameter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that. I'll see how hard it is to get the error for the {string} x case and then remove it when it's changed to {...string} x. We can do the code fix later, since @mhegazy wants to get this into 2.8.1.

1. JS functions that use `arguments` do not require a dummy parameter in
order to get a type for the synthetic `args` parameter if there is an
`@param` with a `...` type.
2.JS functions that use `arguments` and have an `@param` must have a
type that is a `...` type.
@sandersn
Copy link
Member Author

OK, I improved the error message and type for functions that use arguments. They no longer require a dummy parameter to match the jsdoc @param. So I added the error you suggested. Let me know what you think of the wording.

const lastParam = lastOrUndefined(declaration.parameters);
const lastParamTags = lastParam && getJSDocParameterTags(lastParam);
const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) : getJSDocTags(declaration).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) === isJSDocParameterTag

@@ -6761,17 +6761,20 @@ namespace ts {
return links.resolvedSignature;
}

/**
* A JS function gets a synthetic rest parameter if it references `arguments` AND:
* 1. It has no parameters and at least one `@param` and the first `@param` has a type and the type starts with `...`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment says the first @param, but we are looping over all of them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I decided to change the comment in order to continue sharing most of the code here.

Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
idText(node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name));
const decl = getHostSignatureFromJSDoc(node);
if (decl) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to explicitly comment that we decided not to issue errors on @param tags in invalid locations.

@@ -3720,6 +3720,10 @@
"category": "Error",
"code": 8028
},
"JSDoc '...' must appear on the last @param tag of a function that uses 'arguments'.": {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like it's complaining about ... in an invalid location. Would write this backwards: the last tag must have ....

Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
idText(node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name));
}
else if (lastOrUndefined(getJSDocTags(decl).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag))) === node &&
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) === isJSDocParameterTag. Also, inefficient to filter entire array then take the last element, instead of findLast.

So in the following situation we will not create an array type:
/** @param {...number} a * /
function f(a) {}
Because `a` will just be of type `number | undefined`. A synthetic `...args` will also be added, which *will* get an array type.
*/
const lastParamDeclaration = host && last(host.parameters);
if (lastParamDeclaration.symbol === param && isRestParameter(lastParamDeclaration)) {
const lastParamDeclaration = host.parameters.length > 0 && last(host.parameters);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lastOrUndefined

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess so. lastOrUndefined is surprisingly complicated though.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just make the implementation simpler? #22572

@sandersn
Copy link
Member Author

No errors and maxOf2: (a: number, b: number, ...args: any[]) => any.

The error reporting in checkJSDocParameterTag only happens if there is no matching symbol for each @param tag, which there is in this case. And the code in getSignatureFromDeclaration notices the use of arguments with no matching @param, so it adds the synthetic rest parameter.

@sandersn sandersn merged commit 677d860 into master Mar 14, 2018
@sandersn sandersn deleted the no-error-on-unmatchable-param-tags branch March 14, 2018 17:18
@ghost
Copy link

ghost commented Mar 14, 2018

The error message currently says The last @param tag of a function that uses 'arguments' must have an array type., which isn't true if it could match the last parameter. Maybe it should say "@param tag has no matching parameter. It could match 'arguments' if it had an array type." or something.

@sandersn
Copy link
Member Author

sandersn commented Mar 14, 2018

Or maybe just "The last unmatched @param ..." ? I think that makes the conditions too complex to read easily.

I like "JSDoc @param tag has name {0} but there is no parameter with that name. It would match arguments if it had an array type." That way the normal error is a substring of the special-case one.

sandersn added a commit that referenced this pull request Mar 14, 2018
* No errr on unmatchable `@param` tags

Such as when the initializer is not a function, or when the function
mentions `arguments` in its body.

* Do not require dummy param for JS uses of arguments

1. JS functions that use `arguments` do not require a dummy parameter in
order to get a type for the synthetic `args` parameter if there is an
`@param` with a `...` type.
2.JS functions that use `arguments` and have an `@param` must have a
type that is a `...` type.

* Check for array type instead of syntactic `...`

* Address PR comments

* Update baselines
@sandersn
Copy link
Member Author

This is now in release 2.8.

@ghost
Copy link

ghost commented Mar 14, 2018

JSDoc @param tag has name {0} but there is no parameter with that name. It would match arguments if it had an array type.

👍

@sandersn
Copy link
Member Author

#22577 improves the message.

sandersn added a commit that referenced this pull request Mar 14, 2018
From #22510 and #22514, which remove lots of bogus `@param` errors and
add lots of `Object is possibly undefined` errors, respectively.

There are quite a few effects of the correct addition of undefined to
types based on postfix= in jsdoc, actually.
sandersn added a commit that referenced this pull request Mar 14, 2018
From #22510 and #22514, which remove lots of bogus `@param` errors and
add lots of `Object is possibly undefined` errors, respectively.

There are quite a few effects of the correct addition of undefined to
types based on postfix= in jsdoc, actually.
@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant