aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp/source/completion/printf.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/lsp/source/completion/printf.go')
-rw-r--r--internal/lsp/source/completion/printf.go172
1 files changed, 0 insertions, 172 deletions
diff --git a/internal/lsp/source/completion/printf.go b/internal/lsp/source/completion/printf.go
deleted file mode 100644
index ce74af53b..000000000
--- a/internal/lsp/source/completion/printf.go
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package completion
-
-import (
- "go/ast"
- "go/constant"
- "go/types"
- "strconv"
- "strings"
- "unicode/utf8"
-)
-
-// printfArgKind returns the expected objKind when completing a
-// printf-like operand. call is the printf-like function call, and
-// argIdx is the index of call.Args being completed.
-func printfArgKind(info *types.Info, call *ast.CallExpr, argIdx int) objKind {
- // Printf-like function name must end in "f".
- fn := exprObj(info, call.Fun)
- if fn == nil || !strings.HasSuffix(fn.Name(), "f") {
- return kindAny
- }
-
- sig, _ := fn.Type().(*types.Signature)
- if sig == nil {
- return kindAny
- }
-
- // Must be variadic and take at least two params.
- numParams := sig.Params().Len()
- if !sig.Variadic() || numParams < 2 || argIdx < numParams-1 {
- return kindAny
- }
-
- // Param preceding variadic args must be a (format) string.
- if !types.Identical(sig.Params().At(numParams-2).Type(), types.Typ[types.String]) {
- return kindAny
- }
-
- // Format string must be a constant.
- strArg := info.Types[call.Args[numParams-2]].Value
- if strArg == nil || strArg.Kind() != constant.String {
- return kindAny
- }
-
- return formatOperandKind(constant.StringVal(strArg), argIdx-(numParams-1)+1)
-}
-
-// formatOperandKind returns the objKind corresponding to format's
-// operandIdx'th operand.
-func formatOperandKind(format string, operandIdx int) objKind {
- var (
- prevOperandIdx int
- kind = kindAny
- )
- for {
- i := strings.Index(format, "%")
- if i == -1 {
- break
- }
-
- var operands []formatOperand
- format, operands = parsePrintfVerb(format[i+1:], prevOperandIdx)
-
- // Check if any this verb's operands correspond to our target
- // operandIdx.
- for _, v := range operands {
- if v.idx == operandIdx {
- if kind == kindAny {
- kind = v.kind
- } else if v.kind != kindAny {
- // If multiple verbs refer to the same operand, take the
- // intersection of their kinds.
- kind &= v.kind
- }
- }
-
- prevOperandIdx = v.idx
- }
- }
- return kind
-}
-
-type formatOperand struct {
- // idx is the one-based printf operand index.
- idx int
- // kind is a mask of expected kinds of objects for this operand.
- kind objKind
-}
-
-// parsePrintfVerb parses the leading printf verb in f. The opening
-// "%" must already be trimmed from f. prevIdx is the previous
-// operand's index, or zero if this is the first verb. The format
-// string is returned with the leading verb removed. Multiple operands
-// can be returned in the case of dynamic widths such as "%*.*f".
-func parsePrintfVerb(f string, prevIdx int) (string, []formatOperand) {
- var verbs []formatOperand
-
- addVerb := func(k objKind) {
- verbs = append(verbs, formatOperand{
- idx: prevIdx + 1,
- kind: k,
- })
- prevIdx++
- }
-
- for len(f) > 0 {
- // Trim first rune off of f so we are guaranteed to make progress.
- r, l := utf8.DecodeRuneInString(f)
- f = f[l:]
-
- // We care about three things:
- // 1. The verb, which maps directly to object kind.
- // 2. Explicit operand indices like "%[2]s".
- // 3. Dynamic widths using "*".
- switch r {
- case '%':
- return f, nil
- case '*':
- addVerb(kindInt)
- continue
- case '[':
- // Parse operand index as in "%[2]s".
- i := strings.Index(f, "]")
- if i == -1 {
- return f, nil
- }
-
- idx, err := strconv.Atoi(f[:i])
- f = f[i+1:]
- if err != nil {
- return f, nil
- }
-
- prevIdx = idx - 1
- continue
- case 'v', 'T':
- addVerb(kindAny)
- case 't':
- addVerb(kindBool)
- case 'c', 'd', 'o', 'O', 'U':
- addVerb(kindInt)
- case 'e', 'E', 'f', 'F', 'g', 'G':
- addVerb(kindFloat | kindComplex)
- case 'b':
- addVerb(kindInt | kindFloat | kindComplex | kindBytes)
- case 'q', 's':
- addVerb(kindString | kindBytes | kindStringer | kindError)
- case 'x', 'X':
- // Omit kindStringer and kindError though technically allowed.
- addVerb(kindString | kindBytes | kindInt | kindFloat | kindComplex)
- case 'p':
- addVerb(kindPtr | kindSlice)
- case 'w':
- addVerb(kindError)
- case '+', '-', '#', ' ', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- // Flag or numeric width/precicision value.
- continue
- default:
- // Assume unrecognized rune is a custom fmt.Formatter verb.
- addVerb(kindAny)
- }
-
- if len(verbs) > 0 {
- break
- }
- }
-
- return f, verbs
-}