From d3e5dac9322eadf5e85144cfdb7cf94ddae0fa35 Mon Sep 17 00:00:00 2001
From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
Date: Wed, 27 Apr 2022 10:49:56 -0700
Subject: [PATCH] Stop tag after @callback from crashing
By copying the kludge in @typedef. @callback's order is simpler, so the
kludge is simpler. However, it's wrong here, and in @typedef. Parsing
tag comments is normally supposed to happen at the end of a tag, but in
@callback and @typedef happens *before* parsing the nested
@param/@property tags.
I still need to figure out what a real fix is -- but for the beta,
copying the existing crash-avoidance kludge from @typedef is best
anyway. I added a test case for typedefs for future use as well.
---
src/compiler/parser.ts | 3 ++-
tests/cases/fourslash/jsTagAfterCallback1.ts | 19 +++++++++++++++++++
tests/cases/fourslash/jsTagAfterCallback2.ts | 19 +++++++++++++++++++
tests/cases/fourslash/jsTagAfterTypedef1.ts | 19 +++++++++++++++++++
4 files changed, 59 insertions(+), 1 deletion(-)
create mode 100644 tests/cases/fourslash/jsTagAfterCallback1.ts
create mode 100644 tests/cases/fourslash/jsTagAfterCallback2.ts
create mode 100644 tests/cases/fourslash/jsTagAfterTypedef1.ts
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index e57a3fa98f390..884a5b36e38c1 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -8579,7 +8579,8 @@ namespace ts {
if (!comment) {
comment = parseTrailingTagComments(start, getNodePos(), indent, indentText);
}
- return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start);
+ const end = comment !== undefined ? getNodePos() : typeExpression.end;
+ return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end);
}
function escapedTextsEqual(a: EntityName, b: EntityName): boolean {
diff --git a/tests/cases/fourslash/jsTagAfterCallback1.ts b/tests/cases/fourslash/jsTagAfterCallback1.ts
new file mode 100644
index 0000000000000..cc270afcf399e
--- /dev/null
+++ b/tests/cases/fourslash/jsTagAfterCallback1.ts
@@ -0,0 +1,19 @@
+///
+// @Filename: foo.js
+// @allowJs: true
+// @checkJs: true
+//// /** @callback Listener @yeturn {ListenerBlock} */
+//// /**
+//// * The function used
+//// * /*1*/ settings
+//// */
+//// class /*2*/ListenerBlock {
+//// }
+
+// Force a syntax tree to be created.
+verify.noMatchingBracePositionInCurrentFile(0);
+
+goTo.marker('1');
+edit.insert('fenster');
+
+verify.quickInfoAt('2', 'class ListenerBlock', 'The function used\nfenster settings')
diff --git a/tests/cases/fourslash/jsTagAfterCallback2.ts b/tests/cases/fourslash/jsTagAfterCallback2.ts
new file mode 100644
index 0000000000000..3cfa493f32abf
--- /dev/null
+++ b/tests/cases/fourslash/jsTagAfterCallback2.ts
@@ -0,0 +1,19 @@
+///
+// @Filename: foo.js
+// @allowJs: true
+// @checkJs: true
+//// /** @callback Listener @param x @yeturn {ListenerBlock} */
+//// /**
+//// * The function used
+//// * /*1*/ settings
+//// */
+//// class /*2*/ListenerBlock {
+//// }
+
+// Force a syntax tree to be created.
+verify.noMatchingBracePositionInCurrentFile(0);
+
+goTo.marker('1');
+edit.insert('fenster');
+
+verify.quickInfoAt('2', 'class ListenerBlock', 'The function used\nfenster settings')
diff --git a/tests/cases/fourslash/jsTagAfterTypedef1.ts b/tests/cases/fourslash/jsTagAfterTypedef1.ts
new file mode 100644
index 0000000000000..d0cf99e6f1804
--- /dev/null
+++ b/tests/cases/fourslash/jsTagAfterTypedef1.ts
@@ -0,0 +1,19 @@
+///
+// @Filename: foo.js
+// @allowJs: true
+// @checkJs: true
+//// /** @typedef Lister @property p @yeturn {ListenerBlock} */
+//// /**
+//// * The function used
+//// * /*1*/ settings
+//// */
+//// class /*2*/ListenerBlock {
+//// }
+
+// Force a syntax tree to be created.
+verify.noMatchingBracePositionInCurrentFile(0);
+
+goTo.marker('1');
+edit.insert('fenster');
+
+verify.quickInfoAt('2', 'class ListenerBlock', 'The function used\nfenster settings')