From 0e23b4948d74bbd09b2288ed6aae6b5544b1688e Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 5 Sep 2018 11:14:01 -0700 Subject: [PATCH 1/2] Use nextToken() after parsing a tag name so we can parse type keywords --- src/compiler/checker.ts | 9 +++++---- src/compiler/parser.ts | 13 +++++++------ .../DocComments.parsesCorrectly.@link tags.json | 4 ++-- .../DocComments.parsesCorrectly.templateTag.json | 4 ++-- .../DocComments.parsesCorrectly.templateTag2.json | 4 ++-- .../DocComments.parsesCorrectly.templateTag3.json | 4 ++-- .../DocComments.parsesCorrectly.templateTag4.json | 4 ++-- .../DocComments.parsesCorrectly.templateTag5.json | 4 ++-- .../DocComments.parsesCorrectly.templateTag6.json | 4 ++-- tests/baselines/reference/enumTag.errors.txt | 2 +- tests/baselines/reference/enumTag.symbols | 2 +- tests/baselines/reference/enumTag.types | 2 +- .../baselines/reference/paramTagWrapping.errors.txt | 8 ++++---- tests/cases/conformance/jsdoc/enumTag.ts | 2 +- 14 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d1a442e8eccc6..466b65d2e5643 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29593,10 +29593,11 @@ namespace ts { } function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) { - const jsdocTypeParameters = isInJavaScriptFile(node) && getJSDocTypeParameterDeclarations(node); - if (node.typeParameters || jsdocTypeParameters && jsdocTypeParameters.length) { - const { pos, end } = node.typeParameters || jsdocTypeParameters && jsdocTypeParameters[0] || node; - return grammarErrorAtPos(node, pos, end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); + const jsdocTypeParameters = isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined; + const range = node.typeParameters || jsdocTypeParameters && firstOrUndefined(jsdocTypeParameters); + if (range) { + const pos = range.pos === range.end ? range.pos : skipTrivia(getSourceFileOfNode(node).text, range.pos); + return grammarErrorAtPos(node, pos, range.end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d1102eb78ac77..a287005681982 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6513,7 +6513,7 @@ namespace ts { } } - function skipWhitespaceOrAsterisk(): void { + function skipWhitespaceOrAsterisk(next: () => void = nextJSDocToken): 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 @@ -6528,7 +6528,7 @@ namespace ts { else if (token() === SyntaxKind.AsteriskToken) { precedingLineBreak = false; } - nextJSDocToken(); + next(); } } @@ -6538,8 +6538,9 @@ namespace ts { atToken.end = scanner.getTextPos(); nextJSDocToken(); - const tagName = parseJSDocIdentifierName(); - skipWhitespaceOrAsterisk(); + // Use 'nextToken' instead of 'nextJsDocToken' so we can parse a type like 'number' in `@enum number` + const tagName = parseJSDocIdentifierName(/*message*/ undefined, nextToken); + skipWhitespaceOrAsterisk(nextToken); let tag: JSDocTag | undefined; switch (tagName.escapedText) { @@ -7113,7 +7114,7 @@ namespace ts { return entity; } - function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { + function parseJSDocIdentifierName(message?: DiagnosticMessage, next: () => void = nextJSDocToken): Identifier { if (!tokenIsIdentifierOrKeyword(token())) { return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); } @@ -7124,7 +7125,7 @@ namespace ts { result.escapedText = escapeLeadingUnderscores(scanner.getTokenText()); finishNode(result, end); - nextJSDocToken(); + next(); return result; } } diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@link tags.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@link tags.json index c694d24037107..2ea60ed3e426a 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@link tags.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@link tags.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTag", "pos": 63, - "end": 68, + "end": 67, "atToken": { "kind": "AtToken", "pos": 63, @@ -22,7 +22,7 @@ }, "length": 1, "pos": 63, - "end": 68 + "end": 67 }, "comment": "{@link first link}\nInside {@link link text} thing" } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json index 4d16157d91d91..cd453fce8c5aa 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json @@ -21,7 +21,7 @@ "typeParameters": { "0": { "kind": "TypeParameter", - "pos": 18, + "pos": 17, "end": 19, "name": { "kind": "Identifier", @@ -31,7 +31,7 @@ } }, "length": 1, - "pos": 18, + "pos": 17, "end": 19 } }, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json index 3f5f2a54ec7c4..bfc59a6a3bbd7 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json @@ -21,7 +21,7 @@ "typeParameters": { "0": { "kind": "TypeParameter", - "pos": 18, + "pos": 17, "end": 19, "name": { "kind": "Identifier", @@ -42,7 +42,7 @@ } }, "length": 2, - "pos": 18, + "pos": 17, "end": 21 } }, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json index 193c5c0eb0141..e6ad0c0d0f310 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json @@ -21,7 +21,7 @@ "typeParameters": { "0": { "kind": "TypeParameter", - "pos": 18, + "pos": 17, "end": 19, "name": { "kind": "Identifier", @@ -42,7 +42,7 @@ } }, "length": 2, - "pos": 18, + "pos": 17, "end": 22 } }, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json index 193c5c0eb0141..e6ad0c0d0f310 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json @@ -21,7 +21,7 @@ "typeParameters": { "0": { "kind": "TypeParameter", - "pos": 18, + "pos": 17, "end": 19, "name": { "kind": "Identifier", @@ -42,7 +42,7 @@ } }, "length": 2, - "pos": 18, + "pos": 17, "end": 22 } }, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json index fca64bcb43044..f09001e97e29b 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json @@ -21,7 +21,7 @@ "typeParameters": { "0": { "kind": "TypeParameter", - "pos": 18, + "pos": 17, "end": 19, "name": { "kind": "Identifier", @@ -42,7 +42,7 @@ } }, "length": 2, - "pos": 18, + "pos": 17, "end": 23 } }, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json index 90158499b175e..566a03b96ea36 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json @@ -21,7 +21,7 @@ "typeParameters": { "0": { "kind": "TypeParameter", - "pos": 18, + "pos": 17, "end": 19, "name": { "kind": "Identifier", @@ -42,7 +42,7 @@ } }, "length": 2, - "pos": 18, + "pos": 17, "end": 24 }, "comment": "Description of type parameters." diff --git a/tests/baselines/reference/enumTag.errors.txt b/tests/baselines/reference/enumTag.errors.txt index 0c2524a1dc1a9..4e995ba885a22 100644 --- a/tests/baselines/reference/enumTag.errors.txt +++ b/tests/baselines/reference/enumTag.errors.txt @@ -15,7 +15,7 @@ tests/cases/conformance/jsdoc/a.js(37,16): error TS2339: Property 'UNKNOWN' does /** @type {number} */ OK_I_GUESS: 2 } - /** @enum {number} */ + /** @enum number */ const Second = { MISTAKE: "end", ~~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/enumTag.symbols b/tests/baselines/reference/enumTag.symbols index ed0c11522f427..a54b9f4a3d8d7 100644 --- a/tests/baselines/reference/enumTag.symbols +++ b/tests/baselines/reference/enumTag.symbols @@ -19,7 +19,7 @@ const Target = { OK_I_GUESS: 2 >OK_I_GUESS : Symbol(OK_I_GUESS, Decl(a.js, 5, 15)) } -/** @enum {number} */ +/** @enum number */ const Second = { >Second : Symbol(Second, Decl(a.js, 10, 5)) diff --git a/tests/baselines/reference/enumTag.types b/tests/baselines/reference/enumTag.types index fa8e537b6f583..a8eddab88c738 100644 --- a/tests/baselines/reference/enumTag.types +++ b/tests/baselines/reference/enumTag.types @@ -25,7 +25,7 @@ const Target = { >OK_I_GUESS : number >2 : 2 } -/** @enum {number} */ +/** @enum number */ const Second = { >Second : { MISTAKE: string; OK: number; FINE: number; } >{ MISTAKE: "end", OK: 1, /** @type {number} */ FINE: 2,} : { MISTAKE: string; OK: number; FINE: number; } diff --git a/tests/baselines/reference/paramTagWrapping.errors.txt b/tests/baselines/reference/paramTagWrapping.errors.txt index 48100f0e7468c..3263443dbac41 100644 --- a/tests/baselines/reference/paramTagWrapping.errors.txt +++ b/tests/baselines/reference/paramTagWrapping.errors.txt @@ -1,5 +1,5 @@ -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(2,10): error TS1003: Identifier expected. +tests/cases/conformance/jsdoc/bad.js(2,10): 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. @@ -27,9 +27,9 @@ tests/cases/conformance/jsdoc/bad.js(9,20): error TS7006: Parameter 'z' implicit ==== 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} diff --git a/tests/cases/conformance/jsdoc/enumTag.ts b/tests/cases/conformance/jsdoc/enumTag.ts index bd740d879a18c..a857d4eccce93 100644 --- a/tests/cases/conformance/jsdoc/enumTag.ts +++ b/tests/cases/conformance/jsdoc/enumTag.ts @@ -11,7 +11,7 @@ const Target = { /** @type {number} */ OK_I_GUESS: 2 } -/** @enum {number} */ +/** @enum number */ const Second = { MISTAKE: "end", OK: 1, From d7354d189fb8eadc2dab7c9374e2d5513934ffe1 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 13 Sep 2018 15:25:13 -0700 Subject: [PATCH 2/2] Make callback to skipWhitespaceOrAsterisk non-optional --- src/compiler/parser.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a287005681982..ff3f1b0e2e0aa 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6513,7 +6513,7 @@ namespace ts { } } - function skipWhitespaceOrAsterisk(next: () => void = nextJSDocToken): void { + function skipWhitespaceOrAsterisk(next: () => void): 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 @@ -6684,7 +6684,7 @@ namespace ts { } function tryParseTypeExpression(): JSDocTypeExpression | undefined { - skipWhitespaceOrAsterisk(); + skipWhitespaceOrAsterisk(nextJSDocToken); return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; } @@ -6724,7 +6724,7 @@ namespace ts { function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number | undefined): JSDocParameterTag | JSDocPropertyTag { let typeExpression = tryParseTypeExpression(); let isNameFirst = !typeExpression; - skipWhitespaceOrAsterisk(); + skipWhitespaceOrAsterisk(nextJSDocToken); const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); skipWhitespace(); @@ -6859,7 +6859,7 @@ namespace ts { function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag { const typeExpression = tryParseTypeExpression(); - skipWhitespaceOrAsterisk(); + skipWhitespaceOrAsterisk(nextJSDocToken); const typedefTag = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); typedefTag.atToken = atToken;