]>
Commit | Line | Data |
---|---|---|
4f4a855d ILT |
1 | // Copyright 2013 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | // Package assign defines an Analyzer that detects useless assignments. | |
6 | package assign | |
7 | ||
8 | // TODO(adonovan): check also for assignments to struct fields inside | |
9 | // methods that are on T instead of *T. | |
10 | ||
11 | import ( | |
5a8ea165 | 12 | "fmt" |
4f4a855d ILT |
13 | "go/ast" |
14 | "go/token" | |
15 | "reflect" | |
16 | ||
17 | "golang.org/x/tools/go/analysis" | |
18 | "golang.org/x/tools/go/analysis/passes/inspect" | |
19 | "golang.org/x/tools/go/analysis/passes/internal/analysisutil" | |
20 | "golang.org/x/tools/go/ast/inspector" | |
21 | ) | |
22 | ||
23 | const Doc = `check for useless assignments | |
24 | ||
25 | This checker reports assignments of the form x = x or a[i] = a[i]. | |
26 | These are almost always useless, and even when they aren't they are | |
27 | usually a mistake.` | |
28 | ||
29 | var Analyzer = &analysis.Analyzer{ | |
30 | Name: "assign", | |
31 | Doc: Doc, | |
32 | Requires: []*analysis.Analyzer{inspect.Analyzer}, | |
33 | Run: run, | |
34 | } | |
35 | ||
36 | func run(pass *analysis.Pass) (interface{}, error) { | |
37 | inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) | |
38 | ||
39 | nodeFilter := []ast.Node{ | |
40 | (*ast.AssignStmt)(nil), | |
41 | } | |
42 | inspect.Preorder(nodeFilter, func(n ast.Node) { | |
43 | stmt := n.(*ast.AssignStmt) | |
44 | if stmt.Tok != token.ASSIGN { | |
45 | return // ignore := | |
46 | } | |
47 | if len(stmt.Lhs) != len(stmt.Rhs) { | |
48 | // If LHS and RHS have different cardinality, they can't be the same. | |
49 | return | |
50 | } | |
51 | for i, lhs := range stmt.Lhs { | |
52 | rhs := stmt.Rhs[i] | |
53 | if analysisutil.HasSideEffects(pass.TypesInfo, lhs) || | |
54 | analysisutil.HasSideEffects(pass.TypesInfo, rhs) { | |
55 | continue // expressions may not be equal | |
56 | } | |
57 | if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) { | |
58 | continue // short-circuit the heavy-weight gofmt check | |
59 | } | |
60 | le := analysisutil.Format(pass.Fset, lhs) | |
61 | re := analysisutil.Format(pass.Fset, rhs) | |
62 | if le == re { | |
5a8ea165 ILT |
63 | pass.Report(analysis.Diagnostic{ |
64 | Pos: stmt.Pos(), Message: fmt.Sprintf("self-assignment of %s to %s", re, le), | |
65 | SuggestedFixes: []analysis.SuggestedFix{ | |
66 | {Message: "Remove", TextEdits: []analysis.TextEdit{ | |
67 | {Pos: stmt.Pos(), End: stmt.End(), NewText: []byte{}}, | |
68 | }}, | |
69 | }, | |
70 | }) | |
4f4a855d ILT |
71 | } |
72 | } | |
73 | }) | |
74 | ||
75 | return nil, nil | |
76 | } |