Skip whitespace or asterisk in JSDoc param type and name (#26067)

This commit is contained in:
Tim Schaub 2018-08-16 17:16:09 -06:00 committed by Nathan Shively-Sanders
parent 746e39e9e9
commit 6fd725f3ea
6 changed files with 203 additions and 3 deletions

View file

@ -6507,6 +6507,25 @@ namespace ts {
}
}
function skipWhitespaceOrAsterisk(): void {
if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
}
}
let precedingLineBreak = scanner.hasPrecedingLineBreak();
while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
if (token() === SyntaxKind.NewLineTrivia) {
precedingLineBreak = true;
}
else if (token() === SyntaxKind.AsteriskToken) {
precedingLineBreak = false;
}
nextJSDocToken();
}
}
function parseTag(indent: number) {
Debug.assert(token() === SyntaxKind.AtToken);
const atToken = <AtToken>createNode(SyntaxKind.AtToken, scanner.getTokenPos());
@ -6514,7 +6533,7 @@ namespace ts {
nextJSDocToken();
const tagName = parseJSDocIdentifierName();
skipWhitespace();
skipWhitespaceOrAsterisk();
let tag: JSDocTag | undefined;
switch (tagName.escapedText) {
@ -6658,7 +6677,7 @@ namespace ts {
}
function tryParseTypeExpression(): JSDocTypeExpression | undefined {
skipWhitespace();
skipWhitespaceOrAsterisk();
return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
}
@ -6698,7 +6717,7 @@ namespace ts {
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number | undefined): JSDocParameterTag | JSDocPropertyTag {
let typeExpression = tryParseTypeExpression();
let isNameFirst = !typeExpression;
skipWhitespace();
skipWhitespaceOrAsterisk();
const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
skipWhitespace();

View file

@ -1933,6 +1933,7 @@ namespace ts {
function scanJSDocToken(): JsDocSyntaxKind {
startPos = tokenPos = pos;
tokenFlags = 0;
if (pos >= end) {
return token = SyntaxKind.EndOfFileToken;
}
@ -1952,6 +1953,7 @@ namespace ts {
return token = SyntaxKind.AtToken;
case CharacterCodes.lineFeed:
case CharacterCodes.carriageReturn:
tokenFlags |= TokenFlags.PrecedingLineBreak;
return token = SyntaxKind.NewLineTrivia;
case CharacterCodes.asterisk:
return token = SyntaxKind.AsteriskToken;

View file

@ -0,0 +1,58 @@
tests/cases/conformance/jsdoc/bad.js(2,11): error TS1003: Identifier expected.
tests/cases/conformance/jsdoc/bad.js(2,11): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
tests/cases/conformance/jsdoc/bad.js(5,4): error TS1003: Identifier expected.
tests/cases/conformance/jsdoc/bad.js(5,4): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
tests/cases/conformance/jsdoc/bad.js(6,19): error TS1003: Identifier expected.
tests/cases/conformance/jsdoc/bad.js(6,19): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
tests/cases/conformance/jsdoc/bad.js(9,14): error TS7006: Parameter 'x' implicitly has an 'any' type.
tests/cases/conformance/jsdoc/bad.js(9,17): error TS7006: Parameter 'y' implicitly has an 'any' type.
tests/cases/conformance/jsdoc/bad.js(9,20): error TS7006: Parameter 'z' implicitly has an 'any' type.
==== tests/cases/conformance/jsdoc/good.js (0 errors) ====
/**
* @param
* {number} x Arg x.
* @param {number}
* y Arg y.
* @param {number} z
* Arg z.
*/
function good(x, y, z) {
}
good(1, 2, 3)
==== tests/cases/conformance/jsdoc/bad.js (9 errors) ====
/**
* @param *
!!! error TS1003: Identifier expected.
!!! error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
* {number} x Arg x.
* @param {number}
* * y Arg y.
!!! error TS1003: Identifier expected.
!!! error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
* @param {number} * z
!!! error TS1003: Identifier expected.
!!! error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
* Arg z.
*/
function bad(x, y, z) {
~
!!! error TS7006: Parameter 'x' implicitly has an 'any' type.
~
!!! error TS7006: Parameter 'y' implicitly has an 'any' type.
~
!!! error TS7006: Parameter 'z' implicitly has an 'any' type.
}
bad(1, 2, 3)

View file

@ -0,0 +1,39 @@
=== tests/cases/conformance/jsdoc/good.js ===
/**
* @param
* {number} x Arg x.
* @param {number}
* y Arg y.
* @param {number} z
* Arg z.
*/
function good(x, y, z) {
>good : Symbol(good, Decl(good.js, 0, 0))
>x : Symbol(x, Decl(good.js, 8, 14))
>y : Symbol(y, Decl(good.js, 8, 16))
>z : Symbol(z, Decl(good.js, 8, 19))
}
good(1, 2, 3)
>good : Symbol(good, Decl(good.js, 0, 0))
=== tests/cases/conformance/jsdoc/bad.js ===
/**
* @param *
* {number} x Arg x.
* @param {number}
* * y Arg y.
* @param {number} * z
* Arg z.
*/
function bad(x, y, z) {
>bad : Symbol(bad, Decl(bad.js, 0, 0))
>x : Symbol(x, Decl(bad.js, 8, 13))
>y : Symbol(y, Decl(bad.js, 8, 15))
>z : Symbol(z, Decl(bad.js, 8, 18))
}
bad(1, 2, 3)
>bad : Symbol(bad, Decl(bad.js, 0, 0))

View file

@ -0,0 +1,47 @@
=== tests/cases/conformance/jsdoc/good.js ===
/**
* @param
* {number} x Arg x.
* @param {number}
* y Arg y.
* @param {number} z
* Arg z.
*/
function good(x, y, z) {
>good : (x: number, y: number, z: number) => void
>x : number
>y : number
>z : number
}
good(1, 2, 3)
>good(1, 2, 3) : void
>good : (x: number, y: number, z: number) => void
>1 : 1
>2 : 2
>3 : 3
=== tests/cases/conformance/jsdoc/bad.js ===
/**
* @param *
* {number} x Arg x.
* @param {number}
* * y Arg y.
* @param {number} * z
* Arg z.
*/
function bad(x, y, z) {
>bad : (x: any, y: any, z: any) => void
>x : any
>y : any
>z : any
}
bad(1, 2, 3)
>bad(1, 2, 3) : void
>bad : (x: any, y: any, z: any) => void
>1 : 1
>2 : 2
>3 : 3

View file

@ -0,0 +1,35 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @strict: true
// @Filename: good.js
/**
* @param
* {number} x Arg x.
* @param {number}
* y Arg y.
* @param {number} z
* Arg z.
*/
function good(x, y, z) {
}
good(1, 2, 3)
// @Filename: bad.js
/**
* @param *
* {number} x Arg x.
* @param {number}
* * y Arg y.
* @param {number} * z
* Arg z.
*/
function bad(x, y, z) {
}
bad(1, 2, 3)