.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / analysis / undeclaredname / undeclared.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/analysis/undeclaredname/undeclared.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/internal/lsp/analysis/undeclaredname/undeclared.go
new file mode 100644 (file)
index 0000000..df24d1d
--- /dev/null
@@ -0,0 +1,128 @@
+// 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 undeclaredname defines an Analyzer that applies suggested fixes
+// to errors of the type "undeclared name: %s".
+package undeclaredname
+
+import (
+       "bytes"
+       "fmt"
+       "go/ast"
+       "go/token"
+       "go/types"
+       "strings"
+
+       "golang.org/x/tools/go/analysis"
+       "golang.org/x/tools/go/ast/astutil"
+       "golang.org/x/tools/internal/analysisinternal"
+       "golang.org/x/tools/internal/span"
+)
+
+const Doc = `suggested fixes for "undeclared name: <>"
+
+This checker provides suggested fixes for type errors of the
+type "undeclared name: <>". It will insert a new statement:
+"<> := ".`
+
+var Analyzer = &analysis.Analyzer{
+       Name:             string(analysisinternal.UndeclaredName),
+       Doc:              Doc,
+       Requires:         []*analysis.Analyzer{},
+       Run:              run,
+       RunDespiteErrors: true,
+}
+
+const undeclaredNamePrefix = "undeclared name: "
+
+func run(pass *analysis.Pass) (interface{}, error) {
+       for _, err := range analysisinternal.GetTypeErrors(pass) {
+               if !FixesError(err.Msg) {
+                       continue
+               }
+               name := strings.TrimPrefix(err.Msg, undeclaredNamePrefix)
+               var file *ast.File
+               for _, f := range pass.Files {
+                       if f.Pos() <= err.Pos && err.Pos < f.End() {
+                               file = f
+                               break
+                       }
+               }
+               if file == nil {
+                       continue
+               }
+
+               // Get the path for the relevant range.
+               path, _ := astutil.PathEnclosingInterval(file, err.Pos, err.Pos)
+               if len(path) < 2 {
+                       continue
+               }
+               ident, ok := path[0].(*ast.Ident)
+               if !ok || ident.Name != name {
+                       continue
+               }
+               // Skip selector expressions because it might be too complex
+               // to try and provide a suggested fix for fields and methods.
+               if _, ok := path[1].(*ast.SelectorExpr); ok {
+                       continue
+               }
+               // TODO(golang.org/issue/34644): Handle call expressions with suggested
+               // fixes to create a function.
+               if _, ok := path[1].(*ast.CallExpr); ok {
+                       continue
+               }
+               tok := pass.Fset.File(file.Pos())
+               if tok == nil {
+                       continue
+               }
+               offset := pass.Fset.Position(err.Pos).Offset
+               end := tok.Pos(offset + len(name))
+               pass.Report(analysis.Diagnostic{
+                       Pos:     err.Pos,
+                       End:     end,
+                       Message: err.Msg,
+               })
+       }
+       return nil, nil
+}
+
+func SuggestedFix(fset *token.FileSet, rng span.Range, content []byte, file *ast.File, _ *types.Package, _ *types.Info) (*analysis.SuggestedFix, error) {
+       pos := rng.Start // don't use the end
+       path, _ := astutil.PathEnclosingInterval(file, pos, pos)
+       if len(path) < 2 {
+               return nil, fmt.Errorf("")
+       }
+       ident, ok := path[0].(*ast.Ident)
+       if !ok {
+               return nil, fmt.Errorf("")
+       }
+       // Get the place to insert the new statement.
+       insertBeforeStmt := analysisinternal.StmtToInsertVarBefore(path)
+       if insertBeforeStmt == nil {
+               return nil, fmt.Errorf("")
+       }
+
+       insertBefore := fset.Position(insertBeforeStmt.Pos()).Offset
+
+       // Get the indent to add on the line after the new statement.
+       // Since this will have a parse error, we can not use format.Source().
+       contentBeforeStmt, indent := content[:insertBefore], "\n"
+       if nl := bytes.LastIndex(contentBeforeStmt, []byte("\n")); nl != -1 {
+               indent = string(contentBeforeStmt[nl:])
+       }
+       // Create the new local variable statement.
+       newStmt := fmt.Sprintf("%s := %s", ident.Name, indent)
+       return &analysis.SuggestedFix{
+               Message: fmt.Sprintf("Create variable \"%s\"", ident.Name),
+               TextEdits: []analysis.TextEdit{{
+                       Pos:     insertBeforeStmt.Pos(),
+                       End:     insertBeforeStmt.Pos(),
+                       NewText: []byte(newStmt),
+               }},
+       }, nil
+}
+
+func FixesError(msg string) bool {
+       return strings.HasPrefix(msg, undeclaredNamePrefix)
+}