aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/lsp/analysis/nonewvars/nonewvars.go
diff options
context:
space:
mode:
Diffstat (limited to 'gopls/internal/lsp/analysis/nonewvars/nonewvars.go')
-rw-r--r--gopls/internal/lsp/analysis/nonewvars/nonewvars.go95
1 files changed, 95 insertions, 0 deletions
diff --git a/gopls/internal/lsp/analysis/nonewvars/nonewvars.go b/gopls/internal/lsp/analysis/nonewvars/nonewvars.go
new file mode 100644
index 000000000..6937b36d1
--- /dev/null
+++ b/gopls/internal/lsp/analysis/nonewvars/nonewvars.go
@@ -0,0 +1,95 @@
+// 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 nonewvars defines an Analyzer that applies suggested fixes
+// to errors of the type "no new variables on left side of :=".
+package nonewvars
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+ "go/token"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+ "golang.org/x/tools/internal/analysisinternal"
+)
+
+const Doc = `suggested fixes for "no new vars on left side of :="
+
+This checker provides suggested fixes for type errors of the
+type "no new vars on left side of :=". For example:
+ z := 1
+ z := 2
+will turn into
+ z := 1
+ z = 2
+`
+
+var Analyzer = &analysis.Analyzer{
+ Name: "nonewvars",
+ Doc: Doc,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: run,
+ RunDespiteErrors: true,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+ if len(pass.TypeErrors) == 0 {
+ return nil, nil
+ }
+
+ nodeFilter := []ast.Node{(*ast.AssignStmt)(nil)}
+ inspect.Preorder(nodeFilter, func(n ast.Node) {
+ assignStmt, _ := n.(*ast.AssignStmt)
+ // We only care about ":=".
+ if assignStmt.Tok != token.DEFINE {
+ return
+ }
+
+ var file *ast.File
+ for _, f := range pass.Files {
+ if f.Pos() <= assignStmt.Pos() && assignStmt.Pos() < f.End() {
+ file = f
+ break
+ }
+ }
+ if file == nil {
+ return
+ }
+
+ for _, err := range pass.TypeErrors {
+ if !FixesError(err.Msg) {
+ continue
+ }
+ if assignStmt.Pos() > err.Pos || err.Pos >= assignStmt.End() {
+ continue
+ }
+ var buf bytes.Buffer
+ if err := format.Node(&buf, pass.Fset, file); err != nil {
+ continue
+ }
+ pass.Report(analysis.Diagnostic{
+ Pos: err.Pos,
+ End: analysisinternal.TypeErrorEndPos(pass.Fset, buf.Bytes(), err.Pos),
+ Message: err.Msg,
+ SuggestedFixes: []analysis.SuggestedFix{{
+ Message: "Change ':=' to '='",
+ TextEdits: []analysis.TextEdit{{
+ Pos: err.Pos,
+ End: err.Pos + 1,
+ }},
+ }},
+ })
+ }
+ })
+ return nil, nil
+}
+
+func FixesError(msg string) bool {
+ return msg == "no new variables on left side of :="
+}