diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index f5c86bcf9cb..56e0a0ae50e 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -158,25 +158,6 @@ namespace ts.JsDoc { } } - /** - * Iterates through 'array' by index and performs the callback on each element of array until the callback - * returns a truthy value, then returns that value. - * If no such value is found, the callback is applied to each element of array and undefined is returned. - */ - function forEachUnique(array: readonly T[] | undefined, callback: (element: T, index: number) => U): U | undefined { - if (array) { - for (let i = 0; i < array.length; i++) { - if (array.indexOf(array[i]) === i) { - const result = callback(array[i], i); - if (result) { - return result; - } - } - } - } - return undefined; - } - export function getJSDocTagNameCompletions(): CompletionEntry[] { return jsDocTagNameCompletionEntries || (jsDocTagNameCompletionEntries = map(jsDocTagNames, tagName => { return { diff --git a/src/services/services.ts b/src/services/services.ts index 6d2a3d08531..e0a088db057 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -527,11 +527,11 @@ namespace ts { let doc = JsDoc.getJsDocCommentsFromDeclarations(declarations); if (doc.length === 0 || declarations.some(hasJSDocInheritDocTag)) { - for (const declaration of declarations) { + forEachUnique(declarations, declaration => { const inheritedDocs = findInheritedJSDocComments(declaration, declaration.symbol.name, checker!); // TODO: GH#18217 // TODO: GH#16312 Return a ReadonlyArray, avoid copying inheritedDocs if (inheritedDocs) doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc); - } + }); } return doc; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index cea78be7151..d0e75c5522f 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1458,6 +1458,25 @@ namespace ts { export function documentSpansEqual(a: DocumentSpan, b: DocumentSpan): boolean { return a.fileName === b.fileName && textSpansEqual(a.textSpan, b.textSpan); } + + /** + * Iterates through 'array' by index and performs the callback on each element of array until the callback + * returns a truthy value, then returns that value. + * If no such value is found, the callback is applied to each element of array and undefined is returned. + */ + export function forEachUnique(array: readonly T[] | undefined, callback: (element: T, index: number) => U): U | undefined { + if (array) { + for (let i = 0; i < array.length; i++) { + if (array.indexOf(array[i]) === i) { + const result = callback(array[i], i); + if (result) { + return result; + } + } + } + } + return undefined; + } } // Display-part writer helpers diff --git a/tests/cases/fourslash/quickInfoInheritedJSDoc.ts b/tests/cases/fourslash/quickInfoInheritedJSDoc.ts new file mode 100644 index 00000000000..7b1f54815b7 --- /dev/null +++ b/tests/cases/fourslash/quickInfoInheritedJSDoc.ts @@ -0,0 +1,14 @@ +/// +// #32708 + +////interface I { +//// /** only once please */ +//// t: T +////} +////interface C extends I { +//// t: T +////} +////declare var cnsb: C & C & C; +////cnsb.t/**/ + +verify.quickInfoAt("", "(property) C.t: never", "only once please");