.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / go / analysis / passes / stringintconv / string.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/analysis/passes/stringintconv/string.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/go/analysis/passes/stringintconv/string.go
new file mode 100644 (file)
index 0000000..7a00590
--- /dev/null
@@ -0,0 +1,126 @@
+// 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 stringintconv defines an Analyzer that flags type conversions
+// from integers to strings.
+package stringintconv
+
+import (
+       "fmt"
+       "go/ast"
+       "go/types"
+
+       "golang.org/x/tools/go/analysis"
+       "golang.org/x/tools/go/analysis/passes/inspect"
+       "golang.org/x/tools/go/ast/inspector"
+)
+
+const Doc = `check for string(int) conversions
+
+This checker flags conversions of the form string(x) where x is an integer
+(but not byte or rune) type. Such conversions are discouraged because they
+return the UTF-8 representation of the Unicode code point x, and not a decimal
+string representation of x as one might expect. Furthermore, if x denotes an
+invalid code point, the conversion cannot be statically rejected.
+
+For conversions that intend on using the code point, consider replacing them
+with string(rune(x)). Otherwise, strconv.Itoa and its equivalents return the
+string representation of the value in the desired base.
+`
+
+var Analyzer = &analysis.Analyzer{
+       Name:     "stringintconv",
+       Doc:      Doc,
+       Requires: []*analysis.Analyzer{inspect.Analyzer},
+       Run:      run,
+}
+
+func typeName(typ types.Type) string {
+       if v, _ := typ.(interface{ Name() string }); v != nil {
+               return v.Name()
+       }
+       if v, _ := typ.(interface{ Obj() *types.TypeName }); v != nil {
+               return v.Obj().Name()
+       }
+       return ""
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+       inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+       nodeFilter := []ast.Node{
+               (*ast.CallExpr)(nil),
+       }
+       inspect.Preorder(nodeFilter, func(n ast.Node) {
+               call := n.(*ast.CallExpr)
+
+               // Retrieve target type name.
+               var tname *types.TypeName
+               switch fun := call.Fun.(type) {
+               case *ast.Ident:
+                       tname, _ = pass.TypesInfo.Uses[fun].(*types.TypeName)
+               case *ast.SelectorExpr:
+                       tname, _ = pass.TypesInfo.Uses[fun.Sel].(*types.TypeName)
+               }
+               if tname == nil {
+                       return
+               }
+               target := tname.Name()
+
+               // Check that target type T in T(v) has an underlying type of string.
+               T, _ := tname.Type().Underlying().(*types.Basic)
+               if T == nil || T.Kind() != types.String {
+                       return
+               }
+               if s := T.Name(); target != s {
+                       target += " (" + s + ")"
+               }
+
+               // Check that type V of v has an underlying integral type that is not byte or rune.
+               if len(call.Args) != 1 {
+                       return
+               }
+               v := call.Args[0]
+               vtyp := pass.TypesInfo.TypeOf(v)
+               V, _ := vtyp.Underlying().(*types.Basic)
+               if V == nil || V.Info()&types.IsInteger == 0 {
+                       return
+               }
+               switch V.Kind() {
+               case types.Byte, types.Rune, types.UntypedRune:
+                       return
+               }
+
+               // Retrieve source type name.
+               source := typeName(vtyp)
+               if source == "" {
+                       return
+               }
+               if s := V.Name(); source != s {
+                       source += " (" + s + ")"
+               }
+               diag := analysis.Diagnostic{
+                       Pos:     n.Pos(),
+                       Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)", source, target),
+                       SuggestedFixes: []analysis.SuggestedFix{
+                               {
+                                       Message: "Did you mean to convert a rune to a string?",
+                                       TextEdits: []analysis.TextEdit{
+                                               {
+                                                       Pos:     v.Pos(),
+                                                       End:     v.Pos(),
+                                                       NewText: []byte("rune("),
+                                               },
+                                               {
+                                                       Pos:     v.End(),
+                                                       End:     v.End(),
+                                                       NewText: []byte(")"),
+                                               },
+                                       },
+                               },
+                       },
+               }
+               pass.Report(diag)
+       })
+       return nil, nil
+}