@@ -28,12 +28,14 @@ import {
2828 getInvokedExpression ,
2929 getPossibleGenericSignatures ,
3030 getPossibleTypeArgumentsInfo ,
31+ getTextOfIdentifierOrLiteral ,
3132 Identifier ,
3233 identity ,
3334 InternalSymbolName ,
3435 isArrayBindingPattern ,
3536 isBinaryExpression ,
3637 isBindingElement ,
38+ isBindingPattern ,
3739 isBlock ,
3840 isCallOrNewExpression ,
3941 isFunctionTypeNode ,
@@ -45,6 +47,7 @@ import {
4547 isMethodDeclaration ,
4648 isNoSubstitutionTemplateLiteral ,
4749 isObjectBindingPattern ,
50+ isOmittedExpression ,
4851 isParameter ,
4952 isPropertyAccessExpression ,
5053 isSourceFile ,
@@ -59,6 +62,7 @@ import {
5962 JsxTagNameExpression ,
6063 last ,
6164 lastOrUndefined ,
65+ lineBreakPart ,
6266 ListFormat ,
6367 map ,
6468 mapToDisplayParts ,
@@ -85,6 +89,7 @@ import {
8589 SyntaxKind ,
8690 TaggedTemplateExpression ,
8791 TemplateExpression ,
92+ textPart ,
8893 TextSpan ,
8994 tryCast ,
9095 TupleTypeReference ,
@@ -795,7 +800,43 @@ function createSignatureHelpParameterForParameter(parameter: Symbol, checker: Ty
795800 } ) ;
796801 const isOptional = checker . isOptionalParameter ( parameter . valueDeclaration as ParameterDeclaration ) ;
797802 const isRest = isTransientSymbol ( parameter ) && ! ! ( parameter . links . checkFlags & CheckFlags . RestParameter ) ;
798- return { name : parameter . name , documentation : parameter . getDocumentationComment ( checker ) , displayParts, isOptional, isRest } ;
803+ let documentation = parameter . getDocumentationComment ( checker ) ;
804+ // A destructured parameter (binding pattern) carries the per-property descriptions on nested
805+ // `@param parent.child` tags, which are not part of the parameter symbol's own documentation.
806+ // Surface those alongside the parameter doc, matching how quick info resolves them on hover.
807+ const destructuredDocumentation = getDestructuredParameterDocumentation ( parameter , checker ) ;
808+ if ( destructuredDocumentation . length ) {
809+ documentation = documentation . length
810+ ? [ ...documentation , lineBreakPart ( ) , ...destructuredDocumentation ]
811+ : destructuredDocumentation ;
812+ }
813+ return { name : parameter . name , documentation, displayParts, isOptional, isRest } ;
814+ }
815+
816+ function getDestructuredParameterDocumentation ( parameter : Symbol , checker : TypeChecker ) : SymbolDisplayPart [ ] {
817+ const declaration = parameter . valueDeclaration ;
818+ if ( ! declaration || ! isParameter ( declaration ) || ! isBindingPattern ( declaration . name ) ) {
819+ return emptyArray ;
820+ }
821+ const objectType = checker . getTypeAtLocation ( declaration . name ) ;
822+ const types = objectType . isUnion ( ) ? objectType . types : [ objectType ] ;
823+ const parts : SymbolDisplayPart [ ] = [ ] ;
824+ for ( const element of declaration . name . elements ) {
825+ if ( isOmittedExpression ( element ) ) continue ;
826+ const nameNode = element . propertyName || element . name ;
827+ if ( ! isIdentifier ( nameNode ) ) continue ;
828+ const propertyName = getTextOfIdentifierOrLiteral ( nameNode ) ;
829+ const propertyDocumentation = firstDefined ( types , type => {
830+ const property = type . getProperty ( propertyName ) ;
831+ const doc = property && property . getDocumentationComment ( checker ) ;
832+ return doc && doc . length ? doc : undefined ;
833+ } ) ;
834+ if ( propertyDocumentation ) {
835+ if ( parts . length ) parts . push ( lineBreakPart ( ) ) ;
836+ parts . push ( textPart ( propertyName ) , textPart ( ": " ) , ...propertyDocumentation ) ;
837+ }
838+ }
839+ return parts ;
799840}
800841
801842function createSignatureHelpParameterForTypeParameter ( typeParameter : TypeParameter , checker : TypeChecker , enclosingDeclaration : Node , sourceFile : SourceFile , printer : Printer ) : SignatureHelpParameter {
0 commit comments