2
2
namespace ts . SignatureHelp {
3
3
const enum InvocationKind { Call , TypeArgs , Contextual }
4
4
interface CallInvocation { readonly kind : InvocationKind . Call ; readonly node : CallLikeExpression ; }
5
- interface TypeArgsInvocation { readonly kind : InvocationKind . TypeArgs ; readonly called : Expression ; }
5
+ interface TypeArgsInvocation { readonly kind : InvocationKind . TypeArgs ; readonly called : Identifier ; }
6
6
interface ContextualInvocation {
7
7
readonly kind : InvocationKind . Contextual ;
8
8
readonly signature : Signature ;
@@ -44,7 +44,7 @@ namespace ts.SignatureHelp {
44
44
cancellationToken . throwIfCancellationRequested ( ) ;
45
45
46
46
// Extra syntactic and semantic filtering of signature help
47
- const candidateInfo = getCandidateInfo ( argumentInfo , typeChecker , sourceFile , startingToken , onlyUseSyntacticOwners ) ;
47
+ const candidateInfo = getCandidateOrTypeInfo ( argumentInfo , typeChecker , sourceFile , startingToken , onlyUseSyntacticOwners ) ;
48
48
cancellationToken . throwIfCancellationRequested ( ) ;
49
49
50
50
if ( ! candidateInfo ) {
@@ -53,29 +53,46 @@ namespace ts.SignatureHelp {
53
53
return isSourceFileJavaScript ( sourceFile ) ? createJavaScriptSignatureHelpItems ( argumentInfo , program , cancellationToken ) : undefined ;
54
54
}
55
55
56
- return typeChecker . runWithCancellationToken ( cancellationToken , typeChecker => createSignatureHelpItems ( candidateInfo . candidates , candidateInfo . resolvedSignature , argumentInfo , sourceFile , typeChecker ) ) ;
56
+ return typeChecker . runWithCancellationToken ( cancellationToken , typeChecker =>
57
+ candidateInfo . kind === CandidateOrTypeKind . Candidate
58
+ ? createSignatureHelpItems ( candidateInfo . candidates , candidateInfo . resolvedSignature , argumentInfo , sourceFile , typeChecker )
59
+ : createTypeHelpItems ( candidateInfo . symbol , argumentInfo , sourceFile , typeChecker ) ) ;
57
60
}
58
61
59
- interface CandidateInfo { readonly candidates : ReadonlyArray < Signature > ; readonly resolvedSignature : Signature ; }
60
- function getCandidateInfo ( { invocation, argumentCount } : ArgumentListInfo , checker : TypeChecker , sourceFile : SourceFile , startingToken : Node , onlyUseSyntacticOwners : boolean ) : CandidateInfo | undefined {
62
+ const enum CandidateOrTypeKind { Candidate , Type }
63
+ interface CandidateInfo {
64
+ readonly kind : CandidateOrTypeKind . Candidate ;
65
+ readonly candidates : ReadonlyArray < Signature > ;
66
+ readonly resolvedSignature : Signature ;
67
+ }
68
+ interface TypeInfo {
69
+ readonly kind : CandidateOrTypeKind . Type ;
70
+ readonly symbol : Symbol ;
71
+ }
72
+
73
+ function getCandidateOrTypeInfo ( { invocation, argumentCount } : ArgumentListInfo , checker : TypeChecker , sourceFile : SourceFile , startingToken : Node , onlyUseSyntacticOwners : boolean ) : CandidateInfo | TypeInfo | undefined {
61
74
switch ( invocation . kind ) {
62
75
case InvocationKind . Call : {
63
76
if ( onlyUseSyntacticOwners && ! isSyntacticOwner ( startingToken , invocation . node , sourceFile ) ) {
64
77
return undefined ;
65
78
}
66
79
const candidates : Signature [ ] = [ ] ;
67
80
const resolvedSignature = checker . getResolvedSignatureForSignatureHelp ( invocation . node , candidates , argumentCount ) ! ; // TODO: GH#18217
68
- return candidates . length === 0 ? undefined : { candidates, resolvedSignature } ;
81
+ return candidates . length === 0 ? undefined : { kind : CandidateOrTypeKind . Candidate , candidates, resolvedSignature } ;
69
82
}
70
83
case InvocationKind . TypeArgs : {
71
- if ( onlyUseSyntacticOwners && ! lessThanFollowsCalledExpression ( startingToken , sourceFile , invocation . called ) ) {
84
+ const { called } = invocation ;
85
+ if ( onlyUseSyntacticOwners && ! containsPrecedingToken ( startingToken , sourceFile , isIdentifier ( called ) ? called . parent : called ) ) {
72
86
return undefined ;
73
87
}
74
- const candidates = getPossibleGenericSignatures ( invocation . called , argumentCount , checker ) ;
75
- return candidates . length === 0 ? undefined : { candidates, resolvedSignature : first ( candidates ) } ;
88
+ const candidates = getPossibleGenericSignatures ( called , argumentCount , checker ) ;
89
+ if ( candidates . length !== 0 ) return { kind : CandidateOrTypeKind . Candidate , candidates, resolvedSignature : first ( candidates ) } ;
90
+
91
+ const symbol = checker . getSymbolAtLocation ( called ) ;
92
+ return symbol && { kind : CandidateOrTypeKind . Type , symbol } ;
76
93
}
77
94
case InvocationKind . Contextual :
78
- return { candidates : [ invocation . signature ] , resolvedSignature : invocation . signature } ;
95
+ return { kind : CandidateOrTypeKind . Candidate , candidates : [ invocation . signature ] , resolvedSignature : invocation . signature } ;
79
96
default :
80
97
return Debug . assertNever ( invocation ) ;
81
98
}
@@ -92,7 +109,7 @@ namespace ts.SignatureHelp {
92
109
return ! ! containingList && contains ( invocationChildren , containingList ) ;
93
110
}
94
111
case SyntaxKind . LessThanToken :
95
- return lessThanFollowsCalledExpression ( startingToken , sourceFile , node . expression ) ;
112
+ return containsPrecedingToken ( startingToken , sourceFile , node . expression ) ;
96
113
default :
97
114
return false ;
98
115
}
@@ -114,12 +131,12 @@ namespace ts.SignatureHelp {
114
131
} ) ) ;
115
132
}
116
133
117
- function lessThanFollowsCalledExpression ( startingToken : Node , sourceFile : SourceFile , calledExpression : Expression ) {
134
+ function containsPrecedingToken ( startingToken : Node , sourceFile : SourceFile , container : Node ) {
118
135
const precedingToken = Debug . assertDefined (
119
136
findPrecedingToken ( startingToken . getFullStart ( ) , sourceFile , startingToken . parent , /*excludeJsdoc*/ true )
120
137
) ;
121
138
122
- return rangeContainsRange ( calledExpression , precedingToken ) ;
139
+ return rangeContainsRange ( container , precedingToken ) ;
123
140
}
124
141
125
142
export interface ArgumentInfoForCompletions {
@@ -457,6 +474,10 @@ namespace ts.SignatureHelp {
457
474
return invocation . kind === InvocationKind . Call ? getInvokedExpression ( invocation . node ) : invocation . called ;
458
475
}
459
476
477
+ function getEnclosingDeclarationFromInvocation ( invocation : Invocation ) : Node {
478
+ return invocation . kind === InvocationKind . Call ? invocation . node : invocation . kind === InvocationKind . TypeArgs ? invocation . called : invocation . node ;
479
+ }
480
+
460
481
const signatureHelpNodeBuilderFlags = NodeBuilderFlags . OmitParameterModifiers | NodeBuilderFlags . IgnoreErrors | NodeBuilderFlags . UseAliasDefinedOutsideCurrentScope ;
461
482
function createSignatureHelpItems (
462
483
candidates : ReadonlyArray < Signature > ,
@@ -465,7 +486,7 @@ namespace ts.SignatureHelp {
465
486
sourceFile : SourceFile ,
466
487
typeChecker : TypeChecker ,
467
488
) : SignatureHelpItems {
468
- const enclosingDeclaration = invocation . kind === InvocationKind . Call ? invocation . node : invocation . kind === InvocationKind . TypeArgs ? invocation . called : invocation . node ;
489
+ const enclosingDeclaration = getEnclosingDeclarationFromInvocation ( invocation ) ;
469
490
const callTargetSymbol = invocation . kind === InvocationKind . Contextual ? invocation . symbol : typeChecker . getSymbolAtLocation ( getExpressionFromInvocation ( invocation ) ) ;
470
491
const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts ( typeChecker , callTargetSymbol , /*enclosingDeclaration*/ undefined , /*meaning*/ undefined ) : emptyArray ;
471
492
const items = candidates . map ( candidateSignature => getSignatureHelpItem ( candidateSignature , callTargetDisplayParts , isTypeParameterList , typeChecker , enclosingDeclaration , sourceFile ) ) ;
@@ -480,11 +501,36 @@ namespace ts.SignatureHelp {
480
501
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount } ;
481
502
}
482
503
504
+ function createTypeHelpItems (
505
+ symbol : Symbol ,
506
+ { argumentCount, argumentsSpan : applicableSpan , invocation, argumentIndex } : ArgumentListInfo ,
507
+ sourceFile : SourceFile ,
508
+ checker : TypeChecker
509
+ ) : SignatureHelpItems | undefined {
510
+ const typeParameters = checker . getLocalTypeParametersOfClassOrInterfaceOrTypeAlias ( symbol ) ;
511
+ if ( ! typeParameters ) return undefined ;
512
+ const items = [ getTypeHelpItem ( symbol , typeParameters , checker , getEnclosingDeclarationFromInvocation ( invocation ) , sourceFile ) ] ;
513
+ return { items, applicableSpan, selectedItemIndex : 0 , argumentIndex, argumentCount } ;
514
+ }
515
+
516
+ function getTypeHelpItem ( symbol : Symbol , typeParameters : ReadonlyArray < TypeParameter > , checker : TypeChecker , enclosingDeclaration : Node , sourceFile : SourceFile ) : SignatureHelpItem {
517
+ const typeSymbolDisplay = symbolToDisplayParts ( checker , symbol ) ;
518
+
519
+ const printer = createPrinter ( { removeComments : true } ) ;
520
+ const parameters = typeParameters . map ( t => createSignatureHelpParameterForTypeParameter ( t , checker , enclosingDeclaration , sourceFile , printer ) ) ;
521
+
522
+ const documentation = symbol . getDocumentationComment ( checker ) ;
523
+ const tags = symbol . getJsDocTags ( ) ;
524
+ const prefixDisplayParts = [ ...typeSymbolDisplay , punctuationPart ( SyntaxKind . LessThanToken ) ] ;
525
+ return { isVariadic : false , prefixDisplayParts, suffixDisplayParts : [ punctuationPart ( SyntaxKind . GreaterThanToken ) ] , separatorDisplayParts, parameters, documentation, tags } ;
526
+ }
527
+
528
+ const separatorDisplayParts : SymbolDisplayPart [ ] = [ punctuationPart ( SyntaxKind . CommaToken ) , spacePart ( ) ] ;
529
+
483
530
function getSignatureHelpItem ( candidateSignature : Signature , callTargetDisplayParts : ReadonlyArray < SymbolDisplayPart > , isTypeParameterList : boolean , checker : TypeChecker , enclosingDeclaration : Node , sourceFile : SourceFile ) : SignatureHelpItem {
484
531
const { isVariadic, parameters, prefix, suffix } = ( isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters ) ( candidateSignature , checker , enclosingDeclaration , sourceFile ) ;
485
532
const prefixDisplayParts = [ ...callTargetDisplayParts , ...prefix ] ;
486
533
const suffixDisplayParts = [ ...suffix , ...returnTypeToDisplayParts ( candidateSignature , enclosingDeclaration , checker ) ] ;
487
- const separatorDisplayParts = [ punctuationPart ( SyntaxKind . CommaToken ) , spacePart ( ) ] ;
488
534
const documentation = candidateSignature . getDocumentationComment ( checker ) ;
489
535
const tags = candidateSignature . getJsDocTags ( ) ;
490
536
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags } ;
0 commit comments