+// Copyright 2013 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 assign defines an Analyzer that detects useless assignments.
+package assign
+
+// TODO(adonovan): check also for assignments to struct fields inside
+// methods that are on T instead of *T.
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "reflect"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/analysis/passes/internal/analysisutil"
+ "golang.org/x/tools/go/ast/inspector"
+)
+
+const Doc = `check for useless assignments
+
+This checker reports assignments of the form x = x or a[i] = a[i].
+These are almost always useless, and even when they aren't they are
+usually a mistake.`
+
+var Analyzer = &analysis.Analyzer{
+ Name: "assign",
+ Doc: Doc,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: run,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+ nodeFilter := []ast.Node{
+ (*ast.AssignStmt)(nil),
+ }
+ inspect.Preorder(nodeFilter, func(n ast.Node) {
+ stmt := n.(*ast.AssignStmt)
+ if stmt.Tok != token.ASSIGN {
+ return // ignore :=
+ }
+ if len(stmt.Lhs) != len(stmt.Rhs) {
+ // If LHS and RHS have different cardinality, they can't be the same.
+ return
+ }
+ for i, lhs := range stmt.Lhs {
+ rhs := stmt.Rhs[i]
+ if analysisutil.HasSideEffects(pass.TypesInfo, lhs) ||
+ analysisutil.HasSideEffects(pass.TypesInfo, rhs) {
+ continue // expressions may not be equal
+ }
+ if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
+ continue // short-circuit the heavy-weight gofmt check
+ }
+ le := analysisutil.Format(pass.Fset, lhs)
+ re := analysisutil.Format(pass.Fset, rhs)
+ if le == re {
+ pass.Report(analysis.Diagnostic{
+ Pos: stmt.Pos(), Message: fmt.Sprintf("self-assignment of %s to %s", re, le),
+ SuggestedFixes: []analysis.SuggestedFix{
+ {Message: "Remove", TextEdits: []analysis.TextEdit{
+ {Pos: stmt.Pos(), End: stmt.End(), NewText: []byte{}},
+ }},
+ },
+ })
+ }
+ }
+ })
+
+ return nil, nil
+}