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  }