golang.org/x/tools/gopls@v0.15.3/internal/golang/completion/literal.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package completion 6 7 import ( 8 "context" 9 "fmt" 10 "go/types" 11 "strings" 12 "unicode" 13 14 "golang.org/x/tools/gopls/internal/golang" 15 "golang.org/x/tools/gopls/internal/golang/completion/snippet" 16 "golang.org/x/tools/gopls/internal/protocol" 17 "golang.org/x/tools/internal/event" 18 ) 19 20 // literal generates composite literal, function literal, and make() 21 // completion items. 22 func (c *completer) literal(ctx context.Context, literalType types.Type, imp *importInfo) { 23 if !c.opts.snippets { 24 return 25 } 26 27 expType := c.inference.objType 28 29 if c.inference.matchesVariadic(literalType) { 30 // Don't offer literal slice candidates for variadic arguments. 31 // For example, don't offer "[]interface{}{}" in "fmt.Print(<>)". 32 return 33 } 34 35 // Avoid literal candidates if the expected type is an empty 36 // interface. It isn't very useful to suggest a literal candidate of 37 // every possible type. 38 if expType != nil && isEmptyInterface(expType) { 39 return 40 } 41 42 // We handle unnamed literal completions explicitly before searching 43 // for candidates. Avoid named-type literal completions for 44 // unnamed-type expected type since that results in duplicate 45 // candidates. For example, in 46 // 47 // type mySlice []int 48 // var []int = <> 49 // 50 // don't offer "mySlice{}" since we have already added a candidate 51 // of "[]int{}". 52 if _, named := literalType.(*types.Named); named && expType != nil { 53 if _, named := golang.Deref(expType).(*types.Named); !named { 54 return 55 } 56 } 57 58 // Check if an object of type literalType would match our expected type. 59 cand := candidate{ 60 obj: c.fakeObj(literalType), 61 } 62 63 switch literalType.Underlying().(type) { 64 // These literal types are addressable (e.g. "&[]int{}"), others are 65 // not (e.g. can't do "&(func(){})"). 66 case *types.Struct, *types.Array, *types.Slice, *types.Map: 67 cand.addressable = true 68 } 69 70 if !c.matchingCandidate(&cand) || cand.convertTo != nil { 71 return 72 } 73 74 var ( 75 qf = c.qf 76 sel = enclosingSelector(c.path, c.pos) 77 ) 78 79 // Don't qualify the type name if we are in a selector expression 80 // since the package name is already present. 81 if sel != nil { 82 qf = func(_ *types.Package) string { return "" } 83 } 84 85 snip, typeName := c.typeNameSnippet(literalType, qf) 86 87 // A type name of "[]int" doesn't work very will with the matcher 88 // since "[" isn't a valid identifier prefix. Here we strip off the 89 // slice (and array) prefix yielding just "int". 90 matchName := typeName 91 switch t := literalType.(type) { 92 case *types.Slice: 93 matchName = types.TypeString(t.Elem(), qf) 94 case *types.Array: 95 matchName = types.TypeString(t.Elem(), qf) 96 } 97 98 addlEdits, err := c.importEdits(imp) 99 if err != nil { 100 event.Error(ctx, "error adding import for literal candidate", err) 101 return 102 } 103 104 // If prefix matches the type name, client may want a composite literal. 105 if score := c.matcher.Score(matchName); score > 0 { 106 if cand.hasMod(reference) { 107 if sel != nil { 108 // If we are in a selector we must place the "&" before the selector. 109 // For example, "foo.B<>" must complete to "&foo.Bar{}", not 110 // "foo.&Bar{}". 111 edits, err := c.editText(sel.Pos(), sel.Pos(), "&") 112 if err != nil { 113 event.Error(ctx, "error making edit for literal pointer completion", err) 114 return 115 } 116 addlEdits = append(addlEdits, edits...) 117 } else { 118 // Otherwise we can stick the "&" directly before the type name. 119 typeName = "&" + typeName 120 snip.PrependText("&") 121 } 122 } 123 124 switch t := literalType.Underlying().(type) { 125 case *types.Struct, *types.Array, *types.Slice, *types.Map: 126 c.compositeLiteral(t, snip.Clone(), typeName, float64(score), addlEdits) 127 case *types.Signature: 128 // Add a literal completion for a signature type that implements 129 // an interface. For example, offer "http.HandlerFunc()" when 130 // expected type is "http.Handler". 131 if expType != nil && types.IsInterface(expType) { 132 c.basicLiteral(t, snip.Clone(), typeName, float64(score), addlEdits) 133 } 134 case *types.Basic: 135 // Add a literal completion for basic types that implement our 136 // expected interface (e.g. named string type http.Dir 137 // implements http.FileSystem), or are identical to our expected 138 // type (i.e. yielding a type conversion such as "float64()"). 139 if expType != nil && (types.IsInterface(expType) || types.Identical(expType, literalType)) { 140 c.basicLiteral(t, snip.Clone(), typeName, float64(score), addlEdits) 141 } 142 } 143 } 144 145 // If prefix matches "make", client may want a "make()" 146 // invocation. We also include the type name to allow for more 147 // flexible fuzzy matching. 148 if score := c.matcher.Score("make." + matchName); !cand.hasMod(reference) && score > 0 { 149 switch literalType.Underlying().(type) { 150 case *types.Slice: 151 // The second argument to "make()" for slices is required, so default to "0". 152 c.makeCall(snip.Clone(), typeName, "0", float64(score), addlEdits) 153 case *types.Map, *types.Chan: 154 // Maps and channels don't require the second argument, so omit 155 // to keep things simple for now. 156 c.makeCall(snip.Clone(), typeName, "", float64(score), addlEdits) 157 } 158 } 159 160 // If prefix matches "func", client may want a function literal. 161 if score := c.matcher.Score("func"); !cand.hasMod(reference) && score > 0 && (expType == nil || !types.IsInterface(expType)) { 162 switch t := literalType.Underlying().(type) { 163 case *types.Signature: 164 c.functionLiteral(ctx, t, float64(score)) 165 } 166 } 167 } 168 169 // literalCandidateScore is the base score for literal candidates. 170 // Literal candidates match the expected type so they should be high 171 // scoring, but we want them ranked below lexical objects of the 172 // correct type, so scale down highScore. 173 const literalCandidateScore = highScore / 2 174 175 // functionLiteral adds a function literal completion item for the 176 // given signature. 177 func (c *completer) functionLiteral(ctx context.Context, sig *types.Signature, matchScore float64) { 178 snip := &snippet.Builder{} 179 snip.WriteText("func(") 180 181 // First we generate names for each param and keep a seen count so 182 // we know if we need to uniquify param names. For example, 183 // "func(int)" will become "func(i int)", but "func(int, int64)" 184 // will become "func(i1 int, i2 int64)". 185 var ( 186 paramNames = make([]string, sig.Params().Len()) 187 paramNameCount = make(map[string]int) 188 hasTypeParams bool 189 ) 190 for i := 0; i < sig.Params().Len(); i++ { 191 var ( 192 p = sig.Params().At(i) 193 name = p.Name() 194 ) 195 196 if tp, _ := p.Type().(*types.TypeParam); tp != nil && !c.typeParamInScope(tp) { 197 hasTypeParams = true 198 } 199 200 if name == "" { 201 // If the param has no name in the signature, guess a name based 202 // on the type. Use an empty qualifier to ignore the package. 203 // For example, we want to name "http.Request" "r", not "hr". 204 typeName, err := golang.FormatVarType(ctx, c.snapshot, c.pkg, p, 205 func(p *types.Package) string { return "" }, 206 func(golang.PackageName, golang.ImportPath, golang.PackagePath) string { return "" }) 207 if err != nil { 208 // In general, the only error we should encounter while formatting is 209 // context cancellation. 210 if ctx.Err() == nil { 211 event.Error(ctx, "formatting var type", err) 212 } 213 return 214 } 215 name = abbreviateTypeName(typeName) 216 } 217 paramNames[i] = name 218 if name != "_" { 219 paramNameCount[name]++ 220 } 221 } 222 223 for n, c := range paramNameCount { 224 // Any names we saw more than once will need a unique suffix added 225 // on. Reset the count to 1 to act as the suffix for the first 226 // name. 227 if c >= 2 { 228 paramNameCount[n] = 1 229 } else { 230 delete(paramNameCount, n) 231 } 232 } 233 234 for i := 0; i < sig.Params().Len(); i++ { 235 if hasTypeParams && !c.opts.placeholders { 236 // If there are type params in the args then the user must 237 // choose the concrete types. If placeholders are disabled just 238 // drop them between the parens and let them fill things in. 239 snip.WritePlaceholder(nil) 240 break 241 } 242 243 if i > 0 { 244 snip.WriteText(", ") 245 } 246 247 var ( 248 p = sig.Params().At(i) 249 name = paramNames[i] 250 ) 251 252 // Uniquify names by adding on an incrementing numeric suffix. 253 if idx, found := paramNameCount[name]; found { 254 paramNameCount[name]++ 255 name = fmt.Sprintf("%s%d", name, idx) 256 } 257 258 if name != p.Name() && c.opts.placeholders { 259 // If we didn't use the signature's param name verbatim then we 260 // may have chosen a poor name. Give the user a placeholder so 261 // they can easily fix the name. 262 snip.WritePlaceholder(func(b *snippet.Builder) { 263 b.WriteText(name) 264 }) 265 } else { 266 snip.WriteText(name) 267 } 268 269 // If the following param's type is identical to this one, omit 270 // this param's type string. For example, emit "i, j int" instead 271 // of "i int, j int". 272 if i == sig.Params().Len()-1 || !types.Identical(p.Type(), sig.Params().At(i+1).Type()) { 273 snip.WriteText(" ") 274 typeStr, err := golang.FormatVarType(ctx, c.snapshot, c.pkg, p, c.qf, c.mq) 275 if err != nil { 276 // In general, the only error we should encounter while formatting is 277 // context cancellation. 278 if ctx.Err() == nil { 279 event.Error(ctx, "formatting var type", err) 280 } 281 return 282 } 283 if sig.Variadic() && i == sig.Params().Len()-1 { 284 typeStr = strings.Replace(typeStr, "[]", "...", 1) 285 } 286 287 if tp, _ := p.Type().(*types.TypeParam); tp != nil && !c.typeParamInScope(tp) { 288 snip.WritePlaceholder(func(snip *snippet.Builder) { 289 snip.WriteText(typeStr) 290 }) 291 } else { 292 snip.WriteText(typeStr) 293 } 294 } 295 } 296 snip.WriteText(")") 297 298 results := sig.Results() 299 if results.Len() > 0 { 300 snip.WriteText(" ") 301 } 302 303 resultsNeedParens := results.Len() > 1 || 304 results.Len() == 1 && results.At(0).Name() != "" 305 306 var resultHasTypeParams bool 307 for i := 0; i < results.Len(); i++ { 308 if tp, _ := results.At(i).Type().(*types.TypeParam); tp != nil && !c.typeParamInScope(tp) { 309 resultHasTypeParams = true 310 } 311 } 312 313 if resultsNeedParens { 314 snip.WriteText("(") 315 } 316 for i := 0; i < results.Len(); i++ { 317 if resultHasTypeParams && !c.opts.placeholders { 318 // Leave an empty tabstop if placeholders are disabled and there 319 // are type args that need specificying. 320 snip.WritePlaceholder(nil) 321 break 322 } 323 324 if i > 0 { 325 snip.WriteText(", ") 326 } 327 r := results.At(i) 328 if name := r.Name(); name != "" { 329 snip.WriteText(name + " ") 330 } 331 332 text, err := golang.FormatVarType(ctx, c.snapshot, c.pkg, r, c.qf, c.mq) 333 if err != nil { 334 // In general, the only error we should encounter while formatting is 335 // context cancellation. 336 if ctx.Err() == nil { 337 event.Error(ctx, "formatting var type", err) 338 } 339 return 340 } 341 if tp, _ := r.Type().(*types.TypeParam); tp != nil && !c.typeParamInScope(tp) { 342 snip.WritePlaceholder(func(snip *snippet.Builder) { 343 snip.WriteText(text) 344 }) 345 } else { 346 snip.WriteText(text) 347 } 348 } 349 if resultsNeedParens { 350 snip.WriteText(")") 351 } 352 353 snip.WriteText(" {") 354 snip.WriteFinalTabstop() 355 snip.WriteText("}") 356 357 c.items = append(c.items, CompletionItem{ 358 Label: "func(...) {}", 359 Score: matchScore * literalCandidateScore, 360 Kind: protocol.VariableCompletion, 361 snippet: snip, 362 }) 363 } 364 365 // conventionalAcronyms contains conventional acronyms for type names 366 // in lower case. For example, "ctx" for "context" and "err" for "error". 367 var conventionalAcronyms = map[string]string{ 368 "context": "ctx", 369 "error": "err", 370 "tx": "tx", 371 "responsewriter": "w", 372 } 373 374 // abbreviateTypeName abbreviates type names into acronyms. For 375 // example, "fooBar" is abbreviated "fb". Care is taken to ignore 376 // non-identifier runes. For example, "[]int" becomes "i", and 377 // "struct { i int }" becomes "s". 378 func abbreviateTypeName(s string) string { 379 var ( 380 b strings.Builder 381 useNextUpper bool 382 ) 383 384 // Trim off leading non-letters. We trim everything between "[" and 385 // "]" to handle array types like "[someConst]int". 386 var inBracket bool 387 s = strings.TrimFunc(s, func(r rune) bool { 388 if inBracket { 389 inBracket = r != ']' 390 return true 391 } 392 393 if r == '[' { 394 inBracket = true 395 } 396 397 return !unicode.IsLetter(r) 398 }) 399 400 if acr, ok := conventionalAcronyms[strings.ToLower(s)]; ok { 401 return acr 402 } 403 404 for i, r := range s { 405 // Stop if we encounter a non-identifier rune. 406 if !unicode.IsLetter(r) && !unicode.IsNumber(r) { 407 break 408 } 409 410 if i == 0 { 411 b.WriteRune(unicode.ToLower(r)) 412 } 413 414 if unicode.IsUpper(r) { 415 if useNextUpper { 416 b.WriteRune(unicode.ToLower(r)) 417 useNextUpper = false 418 } 419 } else { 420 useNextUpper = true 421 } 422 } 423 424 return b.String() 425 } 426 427 // compositeLiteral adds a composite literal completion item for the given typeName. 428 func (c *completer) compositeLiteral(T types.Type, snip *snippet.Builder, typeName string, matchScore float64, edits []protocol.TextEdit) { 429 snip.WriteText("{") 430 // Don't put the tab stop inside the composite literal curlies "{}" 431 // for structs that have no accessible fields. 432 if strct, ok := T.(*types.Struct); !ok || fieldsAccessible(strct, c.pkg.GetTypes()) { 433 snip.WriteFinalTabstop() 434 } 435 snip.WriteText("}") 436 437 nonSnippet := typeName + "{}" 438 439 c.items = append(c.items, CompletionItem{ 440 Label: nonSnippet, 441 InsertText: nonSnippet, 442 Score: matchScore * literalCandidateScore, 443 Kind: protocol.VariableCompletion, 444 AdditionalTextEdits: edits, 445 snippet: snip, 446 }) 447 } 448 449 // basicLiteral adds a literal completion item for the given basic 450 // type name typeName. 451 func (c *completer) basicLiteral(T types.Type, snip *snippet.Builder, typeName string, matchScore float64, edits []protocol.TextEdit) { 452 // Never give type conversions like "untyped int()". 453 if isUntyped(T) { 454 return 455 } 456 457 snip.WriteText("(") 458 snip.WriteFinalTabstop() 459 snip.WriteText(")") 460 461 nonSnippet := typeName + "()" 462 463 c.items = append(c.items, CompletionItem{ 464 Label: nonSnippet, 465 InsertText: nonSnippet, 466 Detail: T.String(), 467 Score: matchScore * literalCandidateScore, 468 Kind: protocol.VariableCompletion, 469 AdditionalTextEdits: edits, 470 snippet: snip, 471 }) 472 } 473 474 // makeCall adds a completion item for a "make()" call given a specific type. 475 func (c *completer) makeCall(snip *snippet.Builder, typeName string, secondArg string, matchScore float64, edits []protocol.TextEdit) { 476 // Keep it simple and don't add any placeholders for optional "make()" arguments. 477 478 snip.PrependText("make(") 479 if secondArg != "" { 480 snip.WriteText(", ") 481 snip.WritePlaceholder(func(b *snippet.Builder) { 482 if c.opts.placeholders { 483 b.WriteText(secondArg) 484 } 485 }) 486 } 487 snip.WriteText(")") 488 489 var nonSnippet strings.Builder 490 nonSnippet.WriteString("make(" + typeName) 491 if secondArg != "" { 492 nonSnippet.WriteString(", ") 493 nonSnippet.WriteString(secondArg) 494 } 495 nonSnippet.WriteByte(')') 496 497 c.items = append(c.items, CompletionItem{ 498 Label: nonSnippet.String(), 499 InsertText: nonSnippet.String(), 500 Score: matchScore * literalCandidateScore, 501 Kind: protocol.FunctionCompletion, 502 AdditionalTextEdits: edits, 503 snippet: snip, 504 }) 505 } 506 507 // Create a snippet for a type name where type params become placeholders. 508 func (c *completer) typeNameSnippet(literalType types.Type, qf types.Qualifier) (*snippet.Builder, string) { 509 var ( 510 snip snippet.Builder 511 typeName string 512 named, _ = literalType.(*types.Named) 513 ) 514 515 if named != nil && named.Obj() != nil && named.TypeParams().Len() > 0 && !c.fullyInstantiated(named) { 516 // We are not "fully instantiated" meaning we have type params that must be specified. 517 if pkg := qf(named.Obj().Pkg()); pkg != "" { 518 typeName = pkg + "." 519 } 520 521 // We do this to get "someType" instead of "someType[T]". 522 typeName += named.Obj().Name() 523 snip.WriteText(typeName + "[") 524 525 if c.opts.placeholders { 526 for i := 0; i < named.TypeParams().Len(); i++ { 527 if i > 0 { 528 snip.WriteText(", ") 529 } 530 snip.WritePlaceholder(func(snip *snippet.Builder) { 531 snip.WriteText(types.TypeString(named.TypeParams().At(i), qf)) 532 }) 533 } 534 } else { 535 snip.WritePlaceholder(nil) 536 } 537 snip.WriteText("]") 538 typeName += "[...]" 539 } else { 540 // We don't have unspecified type params so use default type formatting. 541 typeName = types.TypeString(literalType, qf) 542 snip.WriteText(typeName) 543 } 544 545 return &snip, typeName 546 } 547 548 // fullyInstantiated reports whether all of t's type params have 549 // specified type args. 550 func (c *completer) fullyInstantiated(t *types.Named) bool { 551 tps := t.TypeParams() 552 tas := t.TypeArgs() 553 554 if tps.Len() != tas.Len() { 555 return false 556 } 557 558 for i := 0; i < tas.Len(); i++ { 559 switch ta := tas.At(i).(type) { 560 case *types.TypeParam: 561 // A *TypeParam only counts as specified if it is currently in 562 // scope (i.e. we are in a generic definition). 563 if !c.typeParamInScope(ta) { 564 return false 565 } 566 case *types.Named: 567 if !c.fullyInstantiated(ta) { 568 return false 569 } 570 } 571 } 572 return true 573 } 574 575 // typeParamInScope returns whether tp's object is in scope at c.pos. 576 // This tells you whether you are in a generic definition and can 577 // assume tp has been specified. 578 func (c *completer) typeParamInScope(tp *types.TypeParam) bool { 579 obj := tp.Obj() 580 if obj == nil { 581 return false 582 } 583 584 scope := c.innermostScope() 585 if scope == nil { 586 return false 587 } 588 589 _, foundObj := scope.LookupParent(obj.Name(), c.pos) 590 return obj == foundObj 591 }