@@ -3,6 +3,7 @@ package ls
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "slices"
6
7
"strings"
7
8
8
9
"github.com/microsoft/typescript-go/internal/ast"
@@ -26,7 +27,7 @@ func (l *LanguageService) ProvideHover(ctx context.Context, documentURI lsproto.
26
27
}
27
28
c , done := program .GetTypeCheckerForFile (ctx , file )
28
29
defer done ()
29
- quickInfo , declaration := getQuickInfoAndDeclarationAtLocation (c , node )
30
+ quickInfo , declaration := getQuickInfoAndDeclarationAtLocation (c , getNodeForQuickInfo ( node ) )
30
31
if quickInfo != "" {
31
32
return & lsproto.Hover {
32
33
Contents : lsproto.MarkupContentOrMarkedStringOrMarkedStrings {
@@ -63,6 +64,7 @@ func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, node *ast.Node) (s
63
64
// If the symbol has a type meaning and we're in a type context, remove value-only meanings
64
65
flags &^= ast .SymbolFlagsVariable | ast .SymbolFlagsFunction
65
66
}
67
+ container := getContainerNode (node )
66
68
var b strings.Builder
67
69
if isAlias {
68
70
b .WriteString ("(alias) " )
@@ -93,66 +95,92 @@ func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, node *ast.Node) (s
93
95
}
94
96
}
95
97
}
96
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
98
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
97
99
b .WriteString (": " )
98
- b .WriteString (c .TypeToStringEx (c .GetTypeOfSymbolAtLocation (symbol , node ), nil , typeFormatFlags ))
100
+ b .WriteString (c .TypeToStringEx (c .GetTypeOfSymbolAtLocation (symbol , node ), container , typeFormatFlags ))
99
101
case flags & ast .SymbolFlagsEnumMember != 0 :
100
102
b .WriteString ("(enum member) " )
101
103
t := c .GetTypeOfSymbol (symbol )
102
- b .WriteString (c .TypeToStringEx (t , nil , typeFormatFlags ))
104
+ b .WriteString (c .TypeToStringEx (t , container , typeFormatFlags ))
103
105
if t .Flags ()& checker .TypeFlagsLiteral != 0 {
104
106
b .WriteString (" = " )
105
107
b .WriteString (t .AsLiteralType ().String ())
106
108
}
107
109
case flags & (ast .SymbolFlagsFunction | ast .SymbolFlagsMethod ) != 0 :
108
- signatures := c .GetSignaturesOfType (c .GetTypeOfSymbol (symbol ), checker .SignatureKindCall )
110
+ signatures := getSignaturesAtLocation (c , symbol , checker .SignatureKindCall , node )
111
+ if len (signatures ) == 1 && signatures [0 ].Declaration () != nil {
112
+ declaration = signatures [0 ].Declaration ()
113
+ }
109
114
prefix := core .IfElse (symbol .Flags & ast .SymbolFlagsMethod != 0 , "(method) " , "function " )
110
- writeSignatures (& b , c , signatures , prefix , symbol )
115
+ writeSignatures (& b , c , signatures , container , prefix , symbol )
111
116
case flags & ast .SymbolFlagsConstructor != 0 :
112
- signatures := c .GetSignaturesOfType (c .GetTypeOfSymbol (symbol .Parent ), checker .SignatureKindConstruct )
113
- writeSignatures (& b , c , signatures , "constructor " , symbol .Parent )
117
+ signatures := getSignaturesAtLocation (c , symbol .Parent , checker .SignatureKindConstruct , node )
118
+ if len (signatures ) == 1 && signatures [0 ].Declaration () != nil {
119
+ declaration = signatures [0 ].Declaration ()
120
+ }
121
+ writeSignatures (& b , c , signatures , container , "constructor " , symbol .Parent )
114
122
case flags & (ast .SymbolFlagsClass | ast .SymbolFlagsInterface ) != 0 :
115
- b .WriteString (core .IfElse (symbol .Flags & ast .SymbolFlagsClass != 0 , "class " , "interface " ))
116
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
117
- params := c .GetDeclaredTypeOfSymbol (symbol ).AsInterfaceType ().LocalTypeParameters ()
118
- writeTypeParams (& b , c , params )
123
+ if node .Kind == ast .KindThisKeyword || ast .IsThisInTypeQuery (node ) {
124
+ b .WriteString ("this" )
125
+ } else {
126
+ b .WriteString (core .IfElse (symbol .Flags & ast .SymbolFlagsClass != 0 , "class " , "interface " ))
127
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
128
+ params := c .GetDeclaredTypeOfSymbol (symbol ).AsInterfaceType ().LocalTypeParameters ()
129
+ writeTypeParams (& b , c , params )
130
+ }
119
131
if flags & ast .SymbolFlagsInterface != 0 {
120
132
declaration = core .Find (symbol .Declarations , ast .IsInterfaceDeclaration )
121
133
}
122
134
case flags & ast .SymbolFlagsEnum != 0 :
123
135
b .WriteString ("enum " )
124
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
136
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
125
137
case flags & ast .SymbolFlagsModule != 0 :
126
138
b .WriteString (core .IfElse (symbol .ValueDeclaration != nil && ast .IsSourceFile (symbol .ValueDeclaration ), "module " , "namespace " ))
127
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
139
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
128
140
case flags & ast .SymbolFlagsTypeParameter != 0 :
129
141
b .WriteString ("(type parameter) " )
130
142
tp := c .GetDeclaredTypeOfSymbol (symbol )
131
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
143
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
132
144
cons := c .GetConstraintOfTypeParameter (tp )
133
145
if cons != nil {
134
146
b .WriteString (" extends " )
135
- b .WriteString (c .TypeToStringEx (cons , nil , typeFormatFlags ))
147
+ b .WriteString (c .TypeToStringEx (cons , container , typeFormatFlags ))
136
148
}
137
149
declaration = core .Find (symbol .Declarations , ast .IsTypeParameterDeclaration )
138
150
case flags & ast .SymbolFlagsTypeAlias != 0 :
139
151
b .WriteString ("type " )
140
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
152
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
141
153
writeTypeParams (& b , c , c .GetTypeAliasTypeParameters (symbol ))
142
154
if len (symbol .Declarations ) != 0 {
143
155
b .WriteString (" = " )
144
- b .WriteString (c .TypeToStringEx (c .GetDeclaredTypeOfSymbol (symbol ), nil , typeFormatFlags | checker .TypeFormatFlagsInTypeAlias ))
156
+ b .WriteString (c .TypeToStringEx (c .GetDeclaredTypeOfSymbol (symbol ), container , typeFormatFlags | checker .TypeFormatFlagsInTypeAlias ))
145
157
}
146
158
declaration = core .Find (symbol .Declarations , ast .IsTypeAliasDeclaration )
147
159
case flags & ast .SymbolFlagsAlias != 0 :
148
160
b .WriteString ("import " )
149
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
161
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
150
162
default :
151
- b .WriteString (c .TypeToStringEx (c .GetTypeOfSymbol (symbol ), nil , typeFormatFlags ))
163
+ b .WriteString (c .TypeToStringEx (c .GetTypeOfSymbol (symbol ), container , typeFormatFlags ))
152
164
}
153
165
return b .String (), declaration
154
166
}
155
167
168
+ func getNodeForQuickInfo (node * ast.Node ) * ast.Node {
169
+ if ast .IsNewExpression (node .Parent ) && node .Pos () == node .Parent .Pos () {
170
+ return node .Parent .Expression ()
171
+ }
172
+ if ast .IsNamedTupleMember (node .Parent ) && node .Pos () == node .Parent .Pos () {
173
+ return node .Parent
174
+ }
175
+ if ast .IsImportMeta (node .Parent ) && node .Parent .Name () == node {
176
+ return node .Parent
177
+ }
178
+ if ast .IsJsxNamespacedName (node .Parent ) {
179
+ return node .Parent
180
+ }
181
+ return node
182
+ }
183
+
156
184
func inConstructorContext (node * ast.Node ) bool {
157
185
if node .Kind == ast .KindConstructorKeyword {
158
186
return true
@@ -168,6 +196,30 @@ func inConstructorContext(node *ast.Node) bool {
168
196
return false
169
197
}
170
198
199
+ func getSignaturesAtLocation (c * checker.Checker , symbol * ast.Symbol , kind checker.SignatureKind , node * ast.Node ) []* checker.Signature {
200
+ signatures := c .GetSignaturesOfType (c .GetTypeOfSymbol (symbol ), kind )
201
+ if len (signatures ) > 1 || len (signatures ) == 1 && len (signatures [0 ].TypeParameters ()) != 0 {
202
+ if callNode := getCallOrNewExpression (node ); callNode != nil {
203
+ signature := c .GetResolvedSignature (callNode )
204
+ // If we have a resolved signature, make sure it isn't a synthetic signature
205
+ if signature != nil && (slices .Contains (signatures , signature ) || signature .Target () != nil && slices .Contains (signatures , signature .Target ())) {
206
+ return []* checker.Signature {signature }
207
+ }
208
+ }
209
+ }
210
+ return signatures
211
+ }
212
+
213
+ func getCallOrNewExpression (node * ast.Node ) * ast.Node {
214
+ if ast .IsPropertyAccessExpression (node .Parent ) && node .Parent .Name () == node {
215
+ node = node .Parent
216
+ }
217
+ if ast .IsCallExpression (node .Parent ) || ast .IsNewExpression (node .Parent ) {
218
+ return node .Parent
219
+ }
220
+ return nil
221
+ }
222
+
171
223
func writeTypeParams (b * strings.Builder , c * checker.Checker , params []* checker.Type ) {
172
224
if len (params ) > 0 {
173
225
b .WriteString ("<" )
@@ -187,7 +239,7 @@ func writeTypeParams(b *strings.Builder, c *checker.Checker, params []*checker.T
187
239
}
188
240
}
189
241
190
- func writeSignatures (b * strings.Builder , c * checker.Checker , signatures []* checker.Signature , prefix string , symbol * ast.Symbol ) {
242
+ func writeSignatures (b * strings.Builder , c * checker.Checker , signatures []* checker.Signature , container * ast. Node , prefix string , symbol * ast.Symbol ) {
191
243
for i , sig := range signatures {
192
244
if i != 0 {
193
245
b .WriteString ("\n " )
@@ -197,8 +249,8 @@ func writeSignatures(b *strings.Builder, c *checker.Checker, signatures []*check
197
249
break
198
250
}
199
251
b .WriteString (prefix )
200
- b .WriteString (c .SymbolToStringEx (symbol , nil , ast .SymbolFlagsNone , symbolFormatFlags ))
201
- b .WriteString (c .SignatureToStringEx (sig , nil , typeFormatFlags | checker .TypeFormatFlagsWriteCallStyleSignature ))
252
+ b .WriteString (c .SymbolToStringEx (symbol , container , ast .SymbolFlagsNone , symbolFormatFlags ))
253
+ b .WriteString (c .SignatureToStringEx (sig , container , typeFormatFlags | checker .TypeFormatFlagsWriteCallStyleSignature | checker . TypeFormatFlagsWriteTypeArgumentsOfSignature ))
202
254
}
203
255
}
204
256
0 commit comments