Skip to content

Commit f1dca6a

Browse files
authored
fix(42019): include the jsdoc tags from the base declaration (#42098)
1 parent 822962e commit f1dca6a

14 files changed

+758
-43
lines changed

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2992,7 +2992,7 @@ namespace ts {
29922992
}
29932993

29942994
export function getEffectiveImplementsTypeNodes(node: ClassLikeDeclaration): undefined | readonly ExpressionWithTypeArguments[]{
2995-
if(isInJSFile(node)) {
2995+
if (isInJSFile(node)) {
29962996
return getJSDocImplementsTags(node).map(n => n.class);
29972997
}
29982998
else {

src/services/services.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -550,9 +550,8 @@ namespace ts {
550550

551551
getJsDocTags(): JSDocTagInfo[] {
552552
if (this.jsDocTags === undefined) {
553-
this.jsDocTags = this.declaration ? JsDoc.getJsDocTagsFromDeclarations([this.declaration]) : [];
553+
this.jsDocTags = this.declaration ? getJsDocTags([this.declaration], this.checker) : [];
554554
}
555-
556555
return this.jsDocTags;
557556
}
558557
}
@@ -566,34 +565,37 @@ namespace ts {
566565
return getJSDocTags(node).some(tag => tag.tagName.text === "inheritDoc");
567566
}
568567

568+
function getJsDocTags(declarations: Declaration[], checker: TypeChecker): JSDocTagInfo[] {
569+
let tags = JsDoc.getJsDocTagsFromDeclarations(declarations);
570+
if (tags.length === 0 || declarations.some(hasJSDocInheritDocTag)) {
571+
forEachUnique(declarations, declaration => {
572+
const inheritedTags = findBaseOfDeclaration(checker, declaration, symbol => symbol.getJsDocTags());
573+
if (inheritedTags) {
574+
tags = [...inheritedTags, ...tags];
575+
}
576+
});
577+
}
578+
return tags;
579+
}
580+
569581
function getDocumentationComment(declarations: readonly Declaration[] | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] {
570582
if (!declarations) return emptyArray;
571583

572584
let doc = JsDoc.getJsDocCommentsFromDeclarations(declarations);
573-
if (doc.length === 0 || declarations.some(hasJSDocInheritDocTag)) {
585+
if (checker && (doc.length === 0 || declarations.some(hasJSDocInheritDocTag))) {
574586
forEachUnique(declarations, declaration => {
575-
const inheritedDocs = findInheritedJSDocComments(declaration, declaration.symbol.name, checker!); // TODO: GH#18217
587+
const inheritedDocs = findBaseOfDeclaration(checker, declaration, symbol => symbol.getDocumentationComment(checker));
576588
// TODO: GH#16312 Return a ReadonlyArray, avoid copying inheritedDocs
577589
if (inheritedDocs) doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc);
578590
});
579591
}
580592
return doc;
581593
}
582594

583-
/**
584-
* Attempts to find JSDoc comments for possibly-inherited properties. Checks superclasses then traverses
585-
* implemented interfaces until a symbol is found with the same name and with documentation.
586-
* @param declaration The possibly-inherited declaration to find comments for.
587-
* @param propertyName The name of the possibly-inherited property.
588-
* @param typeChecker A TypeChecker, used to find inherited properties.
589-
* @returns A filled array of documentation comments if any were found, otherwise an empty array.
590-
*/
591-
function findInheritedJSDocComments(declaration: Declaration, propertyName: string, typeChecker: TypeChecker): readonly SymbolDisplayPart[] | undefined {
595+
function findBaseOfDeclaration<T>(checker: TypeChecker, declaration: Declaration, cb: (symbol: Symbol) => T[]): T[] | undefined {
592596
return firstDefined(declaration.parent ? getAllSuperTypeNodes(declaration.parent) : emptyArray, superTypeNode => {
593-
const superType = typeChecker.getTypeAtLocation(superTypeNode);
594-
const baseProperty = superType && typeChecker.getPropertyOfType(superType, propertyName);
595-
const inheritedDocs = baseProperty && baseProperty.getDocumentationComment(typeChecker);
596-
return inheritedDocs && inheritedDocs.length ? inheritedDocs : undefined;
597+
const symbol = checker.getPropertyOfType(checker.getTypeAtLocation(superTypeNode), declaration.symbol.name);
598+
return symbol ? cb(symbol) : undefined;
597599
});
598600
}
599601

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
[
2+
{
3+
"marker": {
4+
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags1.ts",
5+
"position": 298
6+
},
7+
"quickInfo": {
8+
"kind": "function",
9+
"kindModifiers": "",
10+
"textSpan": {
11+
"start": 298,
12+
"length": 3
13+
},
14+
"displayParts": [
15+
{
16+
"text": "function",
17+
"kind": "keyword"
18+
},
19+
{
20+
"text": " ",
21+
"kind": "space"
22+
},
23+
{
24+
"text": "foo",
25+
"kind": "functionName"
26+
},
27+
{
28+
"text": "(",
29+
"kind": "punctuation"
30+
},
31+
{
32+
"text": "x",
33+
"kind": "parameterName"
34+
},
35+
{
36+
"text": ":",
37+
"kind": "punctuation"
38+
},
39+
{
40+
"text": " ",
41+
"kind": "space"
42+
},
43+
{
44+
"text": "any",
45+
"kind": "keyword"
46+
},
47+
{
48+
"text": ")",
49+
"kind": "punctuation"
50+
},
51+
{
52+
"text": ":",
53+
"kind": "punctuation"
54+
},
55+
{
56+
"text": " ",
57+
"kind": "space"
58+
},
59+
{
60+
"text": "void",
61+
"kind": "keyword"
62+
}
63+
],
64+
"documentation": [
65+
{
66+
"text": "Doc",
67+
"kind": "text"
68+
}
69+
],
70+
"tags": [
71+
{
72+
"name": "author",
73+
"text": "Me <[email protected]>"
74+
},
75+
{
76+
"name": "augments",
77+
"text": "C<T> Augments it"
78+
},
79+
{
80+
"name": "template",
81+
"text": "T A template"
82+
},
83+
{
84+
"name": "type",
85+
"text": "{number | string} A type"
86+
},
87+
{
88+
"name": "typedef",
89+
"text": "NumOrStr"
90+
},
91+
{
92+
"name": "property",
93+
"text": "{number} x The prop"
94+
},
95+
{
96+
"name": "param",
97+
"text": "x The param"
98+
},
99+
{
100+
"name": "returns",
101+
"text": "The result"
102+
},
103+
{
104+
"name": "see",
105+
"text": "x (the parameter)"
106+
}
107+
]
108+
}
109+
}
110+
]
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
[
2+
{
3+
"marker": {
4+
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags3.ts",
5+
"position": 290
6+
},
7+
"quickInfo": {
8+
"kind": "method",
9+
"kindModifiers": "",
10+
"textSpan": {
11+
"start": 290,
12+
"length": 6
13+
},
14+
"displayParts": [
15+
{
16+
"text": "(",
17+
"kind": "punctuation"
18+
},
19+
{
20+
"text": "method",
21+
"kind": "text"
22+
},
23+
{
24+
"text": ")",
25+
"kind": "punctuation"
26+
},
27+
{
28+
"text": " ",
29+
"kind": "space"
30+
},
31+
{
32+
"text": "Bar",
33+
"kind": "className"
34+
},
35+
{
36+
"text": ".",
37+
"kind": "punctuation"
38+
},
39+
{
40+
"text": "method",
41+
"kind": "methodName"
42+
},
43+
{
44+
"text": "(",
45+
"kind": "punctuation"
46+
},
47+
{
48+
"text": ")",
49+
"kind": "punctuation"
50+
},
51+
{
52+
"text": ":",
53+
"kind": "punctuation"
54+
},
55+
{
56+
"text": " ",
57+
"kind": "space"
58+
},
59+
{
60+
"text": "void",
61+
"kind": "keyword"
62+
}
63+
],
64+
"documentation": [
65+
{
66+
"text": "comment",
67+
"kind": "text"
68+
}
69+
],
70+
"tags": [
71+
{
72+
"name": "author",
73+
"text": "Me <[email protected]>"
74+
},
75+
{
76+
"name": "see",
77+
"text": "x (the parameter)"
78+
},
79+
{
80+
"name": "param",
81+
"text": "x - x comment"
82+
},
83+
{
84+
"name": "param",
85+
"text": "y - y comment"
86+
},
87+
{
88+
"name": "throws",
89+
"text": "{Error} comment"
90+
}
91+
]
92+
}
93+
}
94+
]

0 commit comments

Comments
 (0)