@@ -342,9 +342,19 @@ namespace ts {
342342 return this . declarations ;
343343 }
344344
345- getDocumentationComment ( ) : SymbolDisplayPart [ ] {
345+ getDocumentationComment ( typeChecker ?: TypeChecker ) : SymbolDisplayPart [ ] {
346346 if ( this . documentationComment === undefined ) {
347347 this . documentationComment = JsDoc . getJsDocCommentsFromDeclarations ( this . declarations ) ;
348+
349+ if ( this . documentationComment . length === 0 && hasJSDocInheritDocTag ( this ) && typeChecker ) {
350+ for ( const declaration of this . getDeclarations ( ) ) {
351+ const inheritedDocs = findInheritedJSDocComments ( declaration , this . getName ( ) , typeChecker ) ;
352+ if ( inheritedDocs . length > 0 ) {
353+ this . documentationComment = inheritedDocs ;
354+ break ;
355+ }
356+ }
357+ }
348358 }
349359
350360 return this . documentationComment ;
@@ -471,9 +481,13 @@ namespace ts {
471481 return this . checker . getReturnTypeOfSignature ( this ) ;
472482 }
473483
474- getDocumentationComment ( ) : SymbolDisplayPart [ ] {
484+ getDocumentationComment ( typeChecker ?: TypeChecker ) : SymbolDisplayPart [ ] {
475485 if ( this . documentationComment === undefined ) {
476486 this . documentationComment = this . declaration ? JsDoc . getJsDocCommentsFromDeclarations ( [ this . declaration ] ) : [ ] ;
487+
488+ if ( this . declaration && this . documentationComment . length === 0 && hasJSDocInheritDocTag ( this ) && typeChecker ) {
489+ this . documentationComment = findInheritedJSDocComments ( this . declaration , this . declaration . symbol . getName ( ) , typeChecker ) ;
490+ }
477491 }
478492
479493 return this . documentationComment ;
@@ -488,6 +502,63 @@ namespace ts {
488502 }
489503 }
490504
505+ /**
506+ * Returns whether or not the given symbol or signature has a JSDoc "inheritDoc" tag on it.
507+ * @param symbol the Symbol or Signature in question.
508+ * @returns `true` if `symbol` has a JSDoc "inheritDoc" tag on it, otherwise `false`.
509+ */
510+ function hasJSDocInheritDocTag ( symbol : Signature | Symbol ) {
511+ return ! ! find ( symbol . getJsDocTags ( ) , tag => tag . name === "inheritDoc" ) ;
512+ }
513+
514+ /**
515+ * Attempts to find JSDoc comments for possibly-inherited properties. Checks superclasses then traverses
516+ * implemented interfaces until a symbol is found with the same name and with documentation.
517+ * @param declaration The possibly-inherited declaration to find comments for.
518+ * @param propertyName The name of the possibly-inherited property.
519+ * @param typeChecker A TypeChecker, used to find inherited properties.
520+ * @returns A filled array of documentation comments if any were found, otherwise an empty array.
521+ */
522+ function findInheritedJSDocComments ( declaration : Declaration , propertyName : string , typeChecker : TypeChecker ) : SymbolDisplayPart [ ] {
523+ let documentationComment : SymbolDisplayPart [ ] = [ ] ;
524+
525+ if ( isClassDeclaration ( declaration . parent ) || isInterfaceDeclaration ( declaration . parent ) ) {
526+ const container : ClassDeclaration | InterfaceDeclaration = declaration . parent ;
527+ const baseTypeNode = getClassExtendsHeritageClauseElement ( container ) ;
528+
529+ if ( baseTypeNode ) {
530+ const baseType = typeChecker . getTypeAtLocation ( baseTypeNode ) ;
531+
532+ // First check superclasses for a property of the same name
533+ let baseProperty = typeChecker . getPropertyOfType ( baseType , propertyName ) ;
534+ let baseDocs = baseProperty ? baseProperty . getDocumentationComment ( typeChecker ) : [ ] ;
535+ if ( baseDocs . length > 0 ) {
536+ documentationComment = baseDocs ;
537+ }
538+
539+ // If there's nothing in the superclass, walk through implemented interfaces left-to-right
540+ if ( documentationComment . length === 0 ) {
541+ const implementedInterfaces = map (
542+ getClassImplementsHeritageClauseElements ( container as ClassLikeDeclaration ) ,
543+ interfaceNode => typeChecker . getTypeAtLocation ( interfaceNode )
544+ ) ;
545+
546+ for ( const implementedInterface of implementedInterfaces ) {
547+ // Use the docs from the first implemented interface to have this property and documentation
548+ baseProperty = typeChecker . getPropertyOfType ( implementedInterface , propertyName ) ;
549+ baseDocs = baseProperty ? baseProperty . getDocumentationComment ( typeChecker ) : [ ] ;
550+ if ( baseDocs . length > 0 ) {
551+ documentationComment = baseDocs ;
552+ break ;
553+ }
554+ }
555+ }
556+ }
557+ }
558+
559+ return documentationComment ;
560+ }
561+
491562 class SourceFileObject extends NodeObject implements SourceFile {
492563 public kind : SyntaxKind . SourceFile ;
493564 public _declarationBrand : any ;
@@ -1370,7 +1441,7 @@ namespace ts {
13701441 kindModifiers : ScriptElementKindModifier . none ,
13711442 textSpan : createTextSpan ( node . getStart ( ) , node . getWidth ( ) ) ,
13721443 displayParts : typeToDisplayParts ( typeChecker , type , getContainerNode ( node ) ) ,
1373- documentation : type . symbol ? type . symbol . getDocumentationComment ( ) : undefined ,
1444+ documentation : type . symbol ? type . symbol . getDocumentationComment ( typeChecker ) : undefined ,
13741445 tags : type . symbol ? type . symbol . getJsDocTags ( ) : undefined
13751446 } ;
13761447 }
0 commit comments