|
9 | 9 | "github.com/microsoft/typescript-go/internal/ast" |
10 | 10 | "github.com/microsoft/typescript-go/internal/astnav" |
11 | 11 | "github.com/microsoft/typescript-go/internal/checker" |
| 12 | + "github.com/microsoft/typescript-go/internal/collections" |
12 | 13 | "github.com/microsoft/typescript-go/internal/core" |
13 | 14 | "github.com/microsoft/typescript-go/internal/lsp/lsproto" |
14 | 15 | ) |
@@ -59,6 +60,9 @@ func (l *LanguageService) ProvideHover(ctx context.Context, documentURI lsproto. |
59 | 60 | } |
60 | 61 |
|
61 | 62 | func (l *LanguageService) getQuickInfoAndDocumentationForSymbol(c *checker.Checker, symbol *ast.Symbol, node *ast.Node, contentFormat lsproto.MarkupKind) (string, string) { |
| 63 | + if symbol == nil { |
| 64 | + return "", "" |
| 65 | + } |
62 | 66 | quickInfo, declaration := getQuickInfoAndDeclarationAtLocation(c, symbol, node) |
63 | 67 | if quickInfo == "" { |
64 | 68 | return "", "" |
@@ -131,149 +135,164 @@ func formatQuickInfo(quickInfo string) string { |
131 | 135 | } |
132 | 136 |
|
133 | 137 | func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, symbol *ast.Symbol, node *ast.Node) (string, *ast.Node) { |
| 138 | + var b strings.Builder |
| 139 | + var visitedAliases collections.Set[*ast.Symbol] |
134 | 140 | container := getContainerNode(node) |
135 | 141 | if node.Kind == ast.KindThisKeyword && ast.IsInExpressionContext(node) { |
136 | 142 | return c.TypeToStringEx(c.GetTypeAtLocation(node), container, typeFormatFlags), nil |
137 | 143 | } |
138 | | - isAlias := symbol != nil && symbol.Flags&ast.SymbolFlagsAlias != 0 |
139 | | - if isAlias { |
140 | | - symbol = c.GetAliasedSymbol(symbol) |
141 | | - } |
142 | | - if symbol == nil || symbol == c.GetUnknownSymbol() { |
143 | | - return "", nil |
144 | | - } |
145 | | - declaration := symbol.ValueDeclaration |
146 | | - flags := symbol.Flags |
147 | | - if flags&ast.SymbolFlagsProperty != 0 && declaration != nil && ast.IsMethodDeclaration(declaration) { |
148 | | - flags = ast.SymbolFlagsMethod |
149 | | - } |
150 | | - if flags&ast.SymbolFlagsType != 0 && (ast.IsPartOfTypeNode(node) || ast.IsTypeDeclarationName(node)) { |
151 | | - // If the symbol has a type meaning and we're in a type context, remove value-only meanings |
152 | | - flags &^= ast.SymbolFlagsVariable | ast.SymbolFlagsFunction |
153 | | - } |
154 | | - var b strings.Builder |
155 | | - if isAlias { |
156 | | - b.WriteString("(alias) ") |
157 | | - } |
158 | | - switch { |
159 | | - case flags&(ast.SymbolFlagsVariable|ast.SymbolFlagsProperty|ast.SymbolFlagsAccessor) != 0: |
160 | | - switch { |
161 | | - case flags&ast.SymbolFlagsProperty != 0: |
162 | | - b.WriteString("(property) ") |
163 | | - case flags&ast.SymbolFlagsAccessor != 0: |
164 | | - b.WriteString("(accessor) ") |
165 | | - default: |
166 | | - decl := symbol.ValueDeclaration |
167 | | - if decl != nil { |
168 | | - switch { |
169 | | - case ast.IsParameter(decl): |
170 | | - b.WriteString("(parameter) ") |
171 | | - case ast.IsVarLet(decl): |
172 | | - b.WriteString("let ") |
173 | | - case ast.IsVarConst(decl): |
174 | | - b.WriteString("const ") |
175 | | - case ast.IsVarUsing(decl): |
176 | | - b.WriteString("using ") |
177 | | - case ast.IsVarAwaitUsing(decl): |
178 | | - b.WriteString("await using ") |
179 | | - default: |
180 | | - b.WriteString("var ") |
181 | | - } |
182 | | - } |
| 144 | + writeSymbolMeaning := func(symbol *ast.Symbol, meaning ast.SymbolFlags, isAlias bool) *ast.Node { |
| 145 | + flags := symbol.Flags & meaning |
| 146 | + if flags == 0 { |
| 147 | + return nil |
183 | 148 | } |
184 | | - if symbol.Name == ast.InternalSymbolNameExportEquals && symbol.Parent != nil && symbol.Parent.Flags&ast.SymbolFlagsModule != 0 { |
185 | | - b.WriteString("exports") |
186 | | - } else { |
187 | | - b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
| 149 | + declaration := symbol.ValueDeclaration |
| 150 | + if flags&ast.SymbolFlagsProperty != 0 && declaration != nil && ast.IsMethodDeclaration(declaration) { |
| 151 | + flags = ast.SymbolFlagsMethod |
188 | 152 | } |
189 | | - b.WriteString(": ") |
190 | | - if callNode := getCallOrNewExpression(node); callNode != nil { |
191 | | - b.WriteString(c.SignatureToStringEx(c.GetResolvedSignature(callNode), container, typeFormatFlags|checker.TypeFormatFlagsWriteCallStyleSignature|checker.TypeFormatFlagsWriteTypeArgumentsOfSignature|checker.TypeFormatFlagsWriteArrowStyleSignature)) |
192 | | - } else { |
193 | | - b.WriteString(c.TypeToStringEx(c.GetTypeOfSymbolAtLocation(symbol, node), container, typeFormatFlags)) |
| 153 | + if b.Len() != 0 { |
| 154 | + b.WriteString("\n") |
194 | 155 | } |
195 | | - case flags&ast.SymbolFlagsEnumMember != 0: |
196 | | - b.WriteString("(enum member) ") |
197 | | - t := c.GetTypeOfSymbol(symbol) |
198 | | - b.WriteString(c.TypeToStringEx(t, container, typeFormatFlags)) |
199 | | - if t.Flags()&checker.TypeFlagsLiteral != 0 { |
200 | | - b.WriteString(" = ") |
201 | | - b.WriteString(t.AsLiteralType().String()) |
| 156 | + if isAlias { |
| 157 | + b.WriteString("(alias) ") |
202 | 158 | } |
203 | | - case flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsMethod) != 0: |
204 | | - prefix := core.IfElse(flags&ast.SymbolFlagsMethod != 0, "(method) ", "function ") |
205 | | - if ast.IsIdentifier(node) && ast.IsFunctionLikeDeclaration(node.Parent) && node.Parent.Name() == node { |
206 | | - declaration = node.Parent |
207 | | - signatures := []*checker.Signature{c.GetSignatureFromDeclaration(declaration)} |
208 | | - writeSignatures(&b, c, signatures, container, prefix, symbol) |
209 | | - } else { |
210 | | - signatures := getSignaturesAtLocation(c, symbol, checker.SignatureKindCall, node) |
211 | | - if len(signatures) == 1 { |
212 | | - if d := signatures[0].Declaration(); d != nil && d.Flags&ast.NodeFlagsJSDoc == 0 { |
213 | | - declaration = d |
| 159 | + switch { |
| 160 | + case flags&(ast.SymbolFlagsVariable|ast.SymbolFlagsProperty|ast.SymbolFlagsAccessor) != 0: |
| 161 | + switch { |
| 162 | + case flags&ast.SymbolFlagsProperty != 0: |
| 163 | + b.WriteString("(property) ") |
| 164 | + case flags&ast.SymbolFlagsAccessor != 0: |
| 165 | + b.WriteString("(accessor) ") |
| 166 | + default: |
| 167 | + decl := symbol.ValueDeclaration |
| 168 | + if decl != nil { |
| 169 | + switch { |
| 170 | + case ast.IsParameter(decl): |
| 171 | + b.WriteString("(parameter) ") |
| 172 | + case ast.IsVarLet(decl): |
| 173 | + b.WriteString("let ") |
| 174 | + case ast.IsVarConst(decl): |
| 175 | + b.WriteString("const ") |
| 176 | + case ast.IsVarUsing(decl): |
| 177 | + b.WriteString("using ") |
| 178 | + case ast.IsVarAwaitUsing(decl): |
| 179 | + b.WriteString("await using ") |
| 180 | + default: |
| 181 | + b.WriteString("var ") |
| 182 | + } |
214 | 183 | } |
215 | 184 | } |
216 | | - writeSignatures(&b, c, signatures, container, prefix, symbol) |
217 | | - } |
218 | | - case flags&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) != 0: |
219 | | - if node.Kind == ast.KindThisKeyword || ast.IsThisInTypeQuery(node) { |
220 | | - b.WriteString("this") |
221 | | - } else if node.Kind == ast.KindConstructorKeyword && (ast.IsConstructorDeclaration(node.Parent) || ast.IsConstructSignatureDeclaration(node.Parent)) { |
222 | | - declaration = node.Parent |
223 | | - signatures := []*checker.Signature{c.GetSignatureFromDeclaration(declaration)} |
224 | | - writeSignatures(&b, c, signatures, container, "constructor ", symbol) |
225 | | - } else { |
226 | | - var signatures []*checker.Signature |
227 | | - if flags&ast.SymbolFlagsClass != 0 && getCallOrNewExpression(node) != nil { |
228 | | - signatures = getSignaturesAtLocation(c, symbol, checker.SignatureKindConstruct, node) |
| 185 | + if symbol.Name == ast.InternalSymbolNameExportEquals && symbol.Parent != nil && symbol.Parent.Flags&ast.SymbolFlagsModule != 0 { |
| 186 | + b.WriteString("exports") |
| 187 | + } else { |
| 188 | + b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
| 189 | + } |
| 190 | + b.WriteString(": ") |
| 191 | + if callNode := getCallOrNewExpression(node); callNode != nil { |
| 192 | + b.WriteString(c.SignatureToStringEx(c.GetResolvedSignature(callNode), container, typeFormatFlags|checker.TypeFormatFlagsWriteCallStyleSignature|checker.TypeFormatFlagsWriteTypeArgumentsOfSignature|checker.TypeFormatFlagsWriteArrowStyleSignature)) |
| 193 | + } else { |
| 194 | + b.WriteString(c.TypeToStringEx(c.GetTypeOfSymbolAtLocation(symbol, node), container, typeFormatFlags)) |
229 | 195 | } |
230 | | - if len(signatures) == 1 { |
231 | | - if d := signatures[0].Declaration(); d != nil && d.Flags&ast.NodeFlagsJSDoc == 0 { |
232 | | - declaration = d |
| 196 | + case flags&ast.SymbolFlagsEnumMember != 0: |
| 197 | + b.WriteString("(enum member) ") |
| 198 | + t := c.GetTypeOfSymbol(symbol) |
| 199 | + b.WriteString(c.TypeToStringEx(t, container, typeFormatFlags)) |
| 200 | + if t.Flags()&checker.TypeFlagsLiteral != 0 { |
| 201 | + b.WriteString(" = ") |
| 202 | + b.WriteString(t.AsLiteralType().String()) |
| 203 | + } |
| 204 | + case flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsMethod) != 0: |
| 205 | + prefix := core.IfElse(flags&ast.SymbolFlagsMethod != 0, "(method) ", "function ") |
| 206 | + if ast.IsIdentifier(node) && ast.IsFunctionLikeDeclaration(node.Parent) && node.Parent.Name() == node { |
| 207 | + declaration = node.Parent |
| 208 | + signatures := []*checker.Signature{c.GetSignatureFromDeclaration(declaration)} |
| 209 | + writeSignatures(&b, c, signatures, container, isAlias, prefix, symbol) |
| 210 | + } else { |
| 211 | + signatures := getSignaturesAtLocation(c, symbol, checker.SignatureKindCall, node) |
| 212 | + if len(signatures) == 1 { |
| 213 | + if d := signatures[0].Declaration(); d != nil && d.Flags&ast.NodeFlagsJSDoc == 0 { |
| 214 | + declaration = d |
| 215 | + } |
233 | 216 | } |
234 | | - writeSignatures(&b, c, signatures, container, "constructor ", symbol) |
| 217 | + writeSignatures(&b, c, signatures, container, isAlias, prefix, symbol) |
| 218 | + } |
| 219 | + case flags&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) != 0: |
| 220 | + if node.Kind == ast.KindThisKeyword || ast.IsThisInTypeQuery(node) { |
| 221 | + b.WriteString("this") |
| 222 | + } else if node.Kind == ast.KindConstructorKeyword && (ast.IsConstructorDeclaration(node.Parent) || ast.IsConstructSignatureDeclaration(node.Parent)) { |
| 223 | + declaration = node.Parent |
| 224 | + signatures := []*checker.Signature{c.GetSignatureFromDeclaration(declaration)} |
| 225 | + writeSignatures(&b, c, signatures, container, isAlias, "constructor ", symbol) |
235 | 226 | } else { |
236 | | - b.WriteString(core.IfElse(flags&ast.SymbolFlagsClass != 0, "class ", "interface ")) |
237 | | - b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
238 | | - params := c.GetDeclaredTypeOfSymbol(symbol).AsInterfaceType().LocalTypeParameters() |
239 | | - writeTypeParams(&b, c, params) |
| 227 | + var signatures []*checker.Signature |
| 228 | + if flags&ast.SymbolFlagsClass != 0 && getCallOrNewExpression(node) != nil { |
| 229 | + signatures = getSignaturesAtLocation(c, symbol, checker.SignatureKindConstruct, node) |
| 230 | + } |
| 231 | + if len(signatures) == 1 { |
| 232 | + if d := signatures[0].Declaration(); d != nil && d.Flags&ast.NodeFlagsJSDoc == 0 { |
| 233 | + declaration = d |
| 234 | + } |
| 235 | + writeSignatures(&b, c, signatures, container, isAlias, "constructor ", symbol) |
| 236 | + } else { |
| 237 | + b.WriteString(core.IfElse(flags&ast.SymbolFlagsClass != 0, "class ", "interface ")) |
| 238 | + b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
| 239 | + params := c.GetDeclaredTypeOfSymbol(symbol).AsInterfaceType().LocalTypeParameters() |
| 240 | + writeTypeParams(&b, c, params) |
| 241 | + } |
240 | 242 | } |
| 243 | + if flags&ast.SymbolFlagsInterface != 0 { |
| 244 | + declaration = core.Find(symbol.Declarations, ast.IsInterfaceDeclaration) |
| 245 | + } |
| 246 | + case flags&ast.SymbolFlagsEnum != 0: |
| 247 | + b.WriteString("enum ") |
| 248 | + b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
| 249 | + case flags&ast.SymbolFlagsModule != 0: |
| 250 | + b.WriteString(core.IfElse(symbol.ValueDeclaration != nil && ast.IsSourceFile(symbol.ValueDeclaration), "module ", "namespace ")) |
| 251 | + b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
| 252 | + case flags&ast.SymbolFlagsTypeParameter != 0: |
| 253 | + b.WriteString("(type parameter) ") |
| 254 | + tp := c.GetDeclaredTypeOfSymbol(symbol) |
| 255 | + b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
| 256 | + cons := c.GetConstraintOfTypeParameter(tp) |
| 257 | + if cons != nil { |
| 258 | + b.WriteString(" extends ") |
| 259 | + b.WriteString(c.TypeToStringEx(cons, container, typeFormatFlags)) |
| 260 | + } |
| 261 | + declaration = core.Find(symbol.Declarations, ast.IsTypeParameterDeclaration) |
| 262 | + case flags&ast.SymbolFlagsTypeAlias != 0: |
| 263 | + b.WriteString("type ") |
| 264 | + b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
| 265 | + writeTypeParams(&b, c, c.GetTypeAliasTypeParameters(symbol)) |
| 266 | + if len(symbol.Declarations) != 0 { |
| 267 | + b.WriteString(" = ") |
| 268 | + b.WriteString(c.TypeToStringEx(c.GetDeclaredTypeOfSymbol(symbol), container, typeFormatFlags|checker.TypeFormatFlagsInTypeAlias)) |
| 269 | + } |
| 270 | + declaration = core.Find(symbol.Declarations, ast.IsTypeAliasDeclaration) |
| 271 | + default: |
| 272 | + b.WriteString(c.TypeToStringEx(c.GetTypeOfSymbol(symbol), container, typeFormatFlags)) |
241 | 273 | } |
242 | | - if flags&ast.SymbolFlagsInterface != 0 { |
243 | | - declaration = core.Find(symbol.Declarations, ast.IsInterfaceDeclaration) |
244 | | - } |
245 | | - case flags&ast.SymbolFlagsEnum != 0: |
246 | | - b.WriteString("enum ") |
247 | | - b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
248 | | - case flags&ast.SymbolFlagsModule != 0: |
249 | | - b.WriteString(core.IfElse(symbol.ValueDeclaration != nil && ast.IsSourceFile(symbol.ValueDeclaration), "module ", "namespace ")) |
250 | | - b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
251 | | - case flags&ast.SymbolFlagsTypeParameter != 0: |
252 | | - b.WriteString("(type parameter) ") |
253 | | - tp := c.GetDeclaredTypeOfSymbol(symbol) |
254 | | - b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
255 | | - cons := c.GetConstraintOfTypeParameter(tp) |
256 | | - if cons != nil { |
257 | | - b.WriteString(" extends ") |
258 | | - b.WriteString(c.TypeToStringEx(cons, container, typeFormatFlags)) |
259 | | - } |
260 | | - declaration = core.Find(symbol.Declarations, ast.IsTypeParameterDeclaration) |
261 | | - case flags&ast.SymbolFlagsTypeAlias != 0: |
262 | | - b.WriteString("type ") |
263 | | - b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
264 | | - writeTypeParams(&b, c, c.GetTypeAliasTypeParameters(symbol)) |
265 | | - if len(symbol.Declarations) != 0 { |
266 | | - b.WriteString(" = ") |
267 | | - b.WriteString(c.TypeToStringEx(c.GetDeclaredTypeOfSymbol(symbol), container, typeFormatFlags|checker.TypeFormatFlagsInTypeAlias)) |
| 274 | + return declaration |
| 275 | + } |
| 276 | + var writeSymbol func(*ast.Symbol, bool) *ast.Node |
| 277 | + writeSymbol = func(symbol *ast.Symbol, isAlias bool) *ast.Node { |
| 278 | + var declaration *ast.Node |
| 279 | + // Recursively write all meanings of alias |
| 280 | + if symbol.Flags&ast.SymbolFlagsAlias != 0 && visitedAliases.AddIfAbsent(symbol) { |
| 281 | + if aliasedSymbol := c.GetAliasedSymbol(symbol); aliasedSymbol != c.GetUnknownSymbol() { |
| 282 | + declaration = writeSymbol(aliasedSymbol, true /*isAlias*/) |
| 283 | + } |
268 | 284 | } |
269 | | - declaration = core.Find(symbol.Declarations, ast.IsTypeAliasDeclaration) |
270 | | - case flags&ast.SymbolFlagsAlias != 0: |
271 | | - b.WriteString("import ") |
272 | | - b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) |
273 | | - default: |
274 | | - b.WriteString(c.TypeToStringEx(c.GetTypeOfSymbol(symbol), container, typeFormatFlags)) |
275 | | - } |
276 | | - return b.String(), declaration |
| 285 | + // Write the value meaning, if any |
| 286 | + declaration = core.OrElse(declaration, writeSymbolMeaning(symbol, ast.SymbolFlagsValue|ast.SymbolFlagsSignature, isAlias)) |
| 287 | + // Write the type meaning, if any |
| 288 | + declaration = core.OrElse(declaration, writeSymbolMeaning(symbol, ast.SymbolFlagsType&^ast.SymbolFlagsValue, isAlias)) |
| 289 | + // Write the namespace meaning, if any |
| 290 | + declaration = core.OrElse(declaration, writeSymbolMeaning(symbol, ast.SymbolFlagsNamespace&^ast.SymbolFlagsValue, isAlias)) |
| 291 | + // Return the first declaration |
| 292 | + return declaration |
| 293 | + } |
| 294 | + firstDeclaration := writeSymbol(symbol, false /*isAlias*/) |
| 295 | + return b.String(), firstDeclaration |
277 | 296 | } |
278 | 297 |
|
279 | 298 | func getNodeForQuickInfo(node *ast.Node) *ast.Node { |
@@ -306,21 +325,6 @@ func getSymbolAtLocationForQuickInfo(c *checker.Checker, node *ast.Node) *ast.Sy |
306 | 325 | return c.GetSymbolAtLocation(node) |
307 | 326 | } |
308 | 327 |
|
309 | | -func inConstructorContext(node *ast.Node) bool { |
310 | | - if node.Kind == ast.KindConstructorKeyword { |
311 | | - return true |
312 | | - } |
313 | | - if ast.IsIdentifier(node) { |
314 | | - for ast.IsRightSideOfQualifiedNameOrPropertyAccess(node) { |
315 | | - node = node.Parent |
316 | | - } |
317 | | - if ast.IsNewExpression(node.Parent) { |
318 | | - return true |
319 | | - } |
320 | | - } |
321 | | - return false |
322 | | -} |
323 | | - |
324 | 328 | func getSignaturesAtLocation(c *checker.Checker, symbol *ast.Symbol, kind checker.SignatureKind, node *ast.Node) []*checker.Signature { |
325 | 329 | signatures := c.GetSignaturesOfType(c.GetTypeOfSymbol(symbol), kind) |
326 | 330 | if len(signatures) > 1 || len(signatures) == 1 && len(signatures[0].TypeParameters()) != 0 { |
@@ -367,10 +371,13 @@ func writeTypeParams(b *strings.Builder, c *checker.Checker, params []*checker.T |
367 | 371 | } |
368 | 372 | } |
369 | 373 |
|
370 | | -func writeSignatures(b *strings.Builder, c *checker.Checker, signatures []*checker.Signature, container *ast.Node, prefix string, symbol *ast.Symbol) { |
| 374 | +func writeSignatures(b *strings.Builder, c *checker.Checker, signatures []*checker.Signature, container *ast.Node, isAlias bool, prefix string, symbol *ast.Symbol) { |
371 | 375 | for i, sig := range signatures { |
372 | 376 | if i != 0 { |
373 | 377 | b.WriteString("\n") |
| 378 | + if isAlias { |
| 379 | + b.WriteString("(alias) ") |
| 380 | + } |
374 | 381 | } |
375 | 382 | if i == 3 && len(signatures) >= 5 { |
376 | 383 | b.WriteString(fmt.Sprintf("// +%v more overloads", len(signatures)-3)) |
|
0 commit comments