fix(42019): include the jsdoc tags from the base declaration (#42098)

This commit is contained in:
Oleksandr T 2021-01-04 17:33:26 +02:00 committed by GitHub
parent 822962e7b3
commit f1dca6a61f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 758 additions and 43 deletions

View File

@ -2992,7 +2992,7 @@ namespace ts {
}
export function getEffectiveImplementsTypeNodes(node: ClassLikeDeclaration): undefined | readonly ExpressionWithTypeArguments[]{
if(isInJSFile(node)) {
if (isInJSFile(node)) {
return getJSDocImplementsTags(node).map(n => n.class);
}
else {

View File

@ -550,9 +550,8 @@ namespace ts {
getJsDocTags(): JSDocTagInfo[] {
if (this.jsDocTags === undefined) {
this.jsDocTags = this.declaration ? JsDoc.getJsDocTagsFromDeclarations([this.declaration]) : [];
this.jsDocTags = this.declaration ? getJsDocTags([this.declaration], this.checker) : [];
}
return this.jsDocTags;
}
}
@ -566,13 +565,26 @@ namespace ts {
return getJSDocTags(node).some(tag => tag.tagName.text === "inheritDoc");
}
function getJsDocTags(declarations: Declaration[], checker: TypeChecker): JSDocTagInfo[] {
let tags = JsDoc.getJsDocTagsFromDeclarations(declarations);
if (tags.length === 0 || declarations.some(hasJSDocInheritDocTag)) {
forEachUnique(declarations, declaration => {
const inheritedTags = findBaseOfDeclaration(checker, declaration, symbol => symbol.getJsDocTags());
if (inheritedTags) {
tags = [...inheritedTags, ...tags];
}
});
}
return tags;
}
function getDocumentationComment(declarations: readonly Declaration[] | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] {
if (!declarations) return emptyArray;
let doc = JsDoc.getJsDocCommentsFromDeclarations(declarations);
if (doc.length === 0 || declarations.some(hasJSDocInheritDocTag)) {
if (checker && (doc.length === 0 || declarations.some(hasJSDocInheritDocTag))) {
forEachUnique(declarations, declaration => {
const inheritedDocs = findInheritedJSDocComments(declaration, declaration.symbol.name, checker!); // TODO: GH#18217
const inheritedDocs = findBaseOfDeclaration(checker, declaration, symbol => symbol.getDocumentationComment(checker));
// TODO: GH#16312 Return a ReadonlyArray, avoid copying inheritedDocs
if (inheritedDocs) doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc);
});
@ -580,20 +592,10 @@ namespace ts {
return doc;
}
/**
* Attempts to find JSDoc comments for possibly-inherited properties. Checks superclasses then traverses
* implemented interfaces until a symbol is found with the same name and with documentation.
* @param declaration The possibly-inherited declaration to find comments for.
* @param propertyName The name of the possibly-inherited property.
* @param typeChecker A TypeChecker, used to find inherited properties.
* @returns A filled array of documentation comments if any were found, otherwise an empty array.
*/
function findInheritedJSDocComments(declaration: Declaration, propertyName: string, typeChecker: TypeChecker): readonly SymbolDisplayPart[] | undefined {
function findBaseOfDeclaration<T>(checker: TypeChecker, declaration: Declaration, cb: (symbol: Symbol) => T[]): T[] | undefined {
return firstDefined(declaration.parent ? getAllSuperTypeNodes(declaration.parent) : emptyArray, superTypeNode => {
const superType = typeChecker.getTypeAtLocation(superTypeNode);
const baseProperty = superType && typeChecker.getPropertyOfType(superType, propertyName);
const inheritedDocs = baseProperty && baseProperty.getDocumentationComment(typeChecker);
return inheritedDocs && inheritedDocs.length ? inheritedDocs : undefined;
const symbol = checker.getPropertyOfType(checker.getTypeAtLocation(superTypeNode), declaration.symbol.name);
return symbol ? cb(symbol) : undefined;
});
}

View File

@ -0,0 +1,110 @@
[
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags1.ts",
"position": 298
},
"quickInfo": {
"kind": "function",
"kindModifiers": "",
"textSpan": {
"start": 298,
"length": 3
},
"displayParts": [
{
"text": "function",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "foo",
"kind": "functionName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": "x",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "any",
"kind": "keyword"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "void",
"kind": "keyword"
}
],
"documentation": [
{
"text": "Doc",
"kind": "text"
}
],
"tags": [
{
"name": "author",
"text": "Me <me@domain.tld>"
},
{
"name": "augments",
"text": "C<T> Augments it"
},
{
"name": "template",
"text": "T A template"
},
{
"name": "type",
"text": "{number | string} A type"
},
{
"name": "typedef",
"text": "NumOrStr"
},
{
"name": "property",
"text": "{number} x The prop"
},
{
"name": "param",
"text": "x The param"
},
{
"name": "returns",
"text": "The result"
},
{
"name": "see",
"text": "x (the parameter)"
}
]
}
}
]

View File

@ -0,0 +1,94 @@
[
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags3.ts",
"position": 290
},
"quickInfo": {
"kind": "method",
"kindModifiers": "",
"textSpan": {
"start": 290,
"length": 6
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "method",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "Bar",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "method",
"kind": "methodName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "void",
"kind": "keyword"
}
],
"documentation": [
{
"text": "comment",
"kind": "text"
}
],
"tags": [
{
"name": "author",
"text": "Me <me@domain.tld>"
},
{
"name": "see",
"text": "x (the parameter)"
},
{
"name": "param",
"text": "x - x comment"
},
{
"name": "param",
"text": "y - y comment"
},
{
"name": "throws",
"text": "{Error} comment"
}
]
}
}
]

View File

@ -0,0 +1,134 @@
[
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags4.ts",
"position": 309
},
"quickInfo": {
"kind": "method",
"kindModifiers": "",
"textSpan": {
"start": 309,
"length": 6
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "method",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "Bar",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "method",
"kind": "methodName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": "x",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
},
{
"text": ",",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "y",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": [
{
"text": "comment",
"kind": "text"
}
],
"tags": [
{
"name": "author",
"text": "Me <me@domain.tld>"
},
{
"name": "see",
"text": "x (the parameter)"
},
{
"name": "param",
"text": "x - x comment"
},
{
"name": "param",
"text": "y - y comment"
},
{
"name": "returns",
"text": "The result"
}
]
}
}
]

View File

@ -0,0 +1,134 @@
[
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags5.js",
"position": 285
},
"quickInfo": {
"kind": "method",
"kindModifiers": "",
"textSpan": {
"start": 285,
"length": 6
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "method",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "Bar",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "method",
"kind": "methodName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": "x",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "any",
"kind": "keyword"
},
{
"text": ",",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "y",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "any",
"kind": "keyword"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": [
{
"text": "comment",
"kind": "text"
}
],
"tags": [
{
"name": "author",
"text": "Me <me@domain.tld>"
},
{
"name": "see",
"text": "x (the parameter)"
},
{
"name": "param",
"text": "x - x comment"
},
{
"name": "param",
"text": "y - y comment"
},
{
"name": "returns",
"text": "The result"
}
]
}
}
]

View File

@ -0,0 +1,137 @@
[
{
"marker": {
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags6.js",
"position": 308
},
"quickInfo": {
"kind": "method",
"kindModifiers": "",
"textSpan": {
"start": 308,
"length": 6
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "method",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "Bar",
"kind": "className"
},
{
"text": ".",
"kind": "punctuation"
},
{
"text": "method",
"kind": "methodName"
},
{
"text": "(",
"kind": "punctuation"
},
{
"text": "x",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "any",
"kind": "keyword"
},
{
"text": ",",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "y",
"kind": "parameterName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "any",
"kind": "keyword"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": [
{
"text": "comment",
"kind": "text"
}
],
"tags": [
{
"name": "author",
"text": "Me <me@domain.tld>"
},
{
"name": "see",
"text": "x (the parameter)"
},
{
"name": "param",
"text": "x - x comment"
},
{
"name": "param",
"text": "y - y comment"
},
{
"name": "returns",
"text": "The result"
},
{
"name": "inheritDoc"
}
]
}
}
]

View File

@ -1,18 +0,0 @@
/// <reference path='fourslash.ts'/>
// @Filename: quickInfoJsDocTags.ts
/////**
//// * Doc
//// * @author Me <me@domain.tld>
//// * @augments {C<T>} Augments it
//// * @template T A template
//// * @type {number | string} A type
//// * @typedef {number | string} NumOrStr
//// * @property {number} x The prop
//// * @param {number} x The param
//// * @returns The result
//// * @see x (the parameter)
//// */
////function /**/foo(x) {}
verify.baselineQuickInfo();

View File

@ -1,7 +1,18 @@
/// <reference path='fourslash.ts'/>
// @Filename: quickInfoJsDocTags1.ts
/////** Doc */
////const /**/x = 0;
verify.quickInfoAt("", "const x: 0", "Doc");
/// <reference path='fourslash.ts'/>
// @Filename: quickInfoJsDocTags1.ts
/////**
//// * Doc
//// * @author Me <me@domain.tld>
//// * @augments {C<T>} Augments it
//// * @template T A template
//// * @type {number | string} A type
//// * @typedef {number | string} NumOrStr
//// * @property {number} x The prop
//// * @param {number} x The param
//// * @returns The result
//// * @see x (the parameter)
//// */
////function /**/foo(x) {}
verify.baselineQuickInfo();

View File

@ -0,0 +1,7 @@
/// <reference path='fourslash.ts'/>
// @Filename: quickInfoJsDocTags2.ts
/////** Doc */
////const /**/x = 0;
verify.quickInfoAt("", "const x: 0", "Doc");

View File

@ -0,0 +1,22 @@
/// <reference path="fourslash.ts" />
// @Filename: quickInfoJsDocTags3.ts
////interface Foo {
//// /**
//// * comment
//// * @author Me <me@domain.tld>
//// * @see x (the parameter)
//// * @param {number} x - x comment
//// * @param {number} y - y comment
//// * @throws {Error} comment
//// */
//// method(x: number, y: number): void;
////}
////
////class Bar implements Foo {
//// /**/method(): void {
//// throw new Error("Method not implemented.");
//// }
////}
verify.baselineQuickInfo();

View File

@ -0,0 +1,25 @@
/// <reference path="fourslash.ts" />
// @Filename: quickInfoJsDocTags4.ts
////class Foo {
//// /**
//// * comment
//// * @author Me <me@domain.tld>
//// * @see x (the parameter)
//// * @param {number} x - x comment
//// * @param {number} y - y comment
//// * @returns The result
//// */
//// method(x: number, y: number): number {
//// return x + y;
//// }
////}
////
////class Bar extends Foo {
//// /**/method(x: number, y: number): number {
//// const res = super.method(x, y) + 100;
//// return res;
//// }
////}
verify.baselineQuickInfo();

View File

@ -0,0 +1,28 @@
/// <reference path="fourslash.ts" />
// @noEmit: true
// @allowJs: true
// @Filename: quickInfoJsDocTags5.js
////class Foo {
//// /**
//// * comment
//// * @author Me <me@domain.tld>
//// * @see x (the parameter)
//// * @param {number} x - x comment
//// * @param {number} y - y comment
//// * @returns The result
//// */
//// method(x, y) {
//// return x + y;
//// }
////}
////
////class Bar extends Foo {
//// /**/method(x, y) {
//// const res = super.method(x, y) + 100;
//// return res;
//// }
////}
verify.baselineQuickInfo();

View File

@ -0,0 +1,29 @@
/// <reference path="fourslash.ts" />
// @noEmit: true
// @allowJs: true
// @Filename: quickInfoJsDocTags6.js
////class Foo {
//// /**
//// * comment
//// * @author Me <me@domain.tld>
//// * @see x (the parameter)
//// * @param {number} x - x comment
//// * @param {number} y - y comment
//// * @returns The result
//// */
//// method(x, y) {
//// return x + y;
//// }
////}
////
////class Bar extends Foo {
//// /** @inheritDoc */
//// /**/method(x, y) {
//// const res = super.method(x, y) + 100;
//// return res;
//// }
////}
verify.baselineQuickInfo();